aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/core/aio.c20
-rw-r--r--src/core/aio.h5
-rw-r--r--src/core/nng_impl.h1
-rw-r--r--src/core/options.c16
-rw-r--r--src/core/options.h9
-rw-r--r--src/core/platform.h157
-rw-r--r--src/core/stream.c366
-rw-r--r--src/core/stream.h69
-rw-r--r--src/core/tcp.h24
-rw-r--r--src/core/transport.c13
-rw-r--r--src/core/transport.h6
-rw-r--r--src/core/url.c45
-rw-r--r--src/core/url.h2
-rw-r--r--src/platform/posix/posix_ipc.h28
-rw-r--r--src/platform/posix/posix_ipcconn.c197
-rw-r--r--src/platform/posix/posix_ipcdial.c100
-rw-r--r--src/platform/posix/posix_ipclisten.c173
-rw-r--r--src/platform/posix/posix_resolv_gai.c7
-rw-r--r--src/platform/posix/posix_tcp.h28
-rw-r--r--src/platform/posix/posix_tcpconn.c186
-rw-r--r--src/platform/posix/posix_tcpdial.c35
-rw-r--r--src/platform/posix/posix_tcplisten.c14
-rw-r--r--src/platform/windows/win_ipc.h43
-rw-r--r--src/platform/windows/win_ipcconn.c145
-rw-r--r--src/platform/windows/win_ipcdial.c149
-rw-r--r--src/platform/windows/win_ipclisten.c195
-rw-r--r--src/platform/windows/win_resolv.c29
-rw-r--r--src/platform/windows/win_tcp.h15
-rw-r--r--src/platform/windows/win_tcpconn.c195
-rw-r--r--src/platform/windows/win_tcpdial.c34
-rw-r--r--src/platform/windows/win_tcplisten.c8
-rw-r--r--src/supplemental/http/http_api.h18
-rw-r--r--src/supplemental/http/http_client.c181
-rw-r--r--src/supplemental/http/http_conn.c125
-rw-r--r--src/supplemental/http/http_server.c192
-rw-r--r--src/supplemental/ipc/CMakeLists.txt16
-rw-r--r--src/supplemental/ipc/ipc.c138
-rw-r--r--src/supplemental/tcp/CMakeLists.txt6
-rw-r--r--src/supplemental/tcp/tcp.c444
-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
-rw-r--r--src/supplemental/websocket/CMakeLists.txt2
-rw-r--r--src/supplemental/websocket/stub.c40
-rw-r--r--src/supplemental/websocket/websocket.c2066
-rw-r--r--src/supplemental/websocket/websocket.h53
-rw-r--r--src/transport/ipc/ipc.c142
-rw-r--r--src/transport/tcp/tcp.c363
-rw-r--r--src/transport/tls/tls.c289
-rw-r--r--src/transport/ws/websocket.c910
52 files changed, 4594 insertions, 3969 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 42224109..3ee94e18 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -73,6 +73,8 @@ set (NNG_SRCS
core/sockimpl.h
core/stats.c
core/stats.h
+ core/stream.c
+ core/stream.h
core/strs.c
core/strs.h
core/taskq.c
@@ -183,7 +185,6 @@ add_subdirectory(transport/zerotier)
add_subdirectory(supplemental/base64)
add_subdirectory(supplemental/http)
-add_subdirectory(supplemental/ipc)
add_subdirectory(supplemental/sha1)
add_subdirectory(supplemental/tcp)
add_subdirectory(supplemental/tls)
diff --git a/src/core/aio.c b/src/core/aio.c
index b67b7467..ee3d10a5 100644
--- a/src/core/aio.c
+++ b/src/core/aio.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>
//
// This software is supplied under the terms of the MIT License, a
@@ -101,6 +101,12 @@ struct nng_aio {
nni_list_node a_prov_node;
void * a_prov_extra[4]; // Extra data used by provider
+ // Socket address. This turns out to be very useful, as we wind up
+ // needing socket addresses for numerous connection related routines.
+ // It would be cleaner to not have this and avoid burning the space,
+ // but having this hear dramatically simplifies lots of code.
+ nng_sockaddr a_sockaddr;
+
// Expire node.
nni_list_node a_expire_node;
};
@@ -765,3 +771,15 @@ nni_aio_sys_init(void)
nni_thr_run(thr);
return (0);
}
+
+void
+nni_aio_set_sockaddr(nni_aio *aio, const nng_sockaddr *sa)
+{
+ memcpy(&aio->a_sockaddr, sa, sizeof(*sa));
+}
+
+void
+nni_aio_get_sockaddr(nni_aio *aio, nng_sockaddr *sa)
+{
+ memcpy(sa, &aio->a_sockaddr, sizeof(*sa));
+} \ No newline at end of file
diff --git a/src/core/aio.h b/src/core/aio.h
index fed0acd8..304f184c 100644
--- a/src/core/aio.h
+++ b/src/core/aio.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>
//
// This software is supplied under the terms of the MIT License, a
@@ -148,6 +148,9 @@ extern void nni_aio_get_iov(nni_aio *, unsigned *, nni_iov **);
extern void nni_aio_normalize_timeout(nni_aio *, nng_duration);
extern void nni_aio_bump_count(nni_aio *, size_t);
+extern void nni_aio_set_sockaddr(nni_aio *aio, const nng_sockaddr *);
+extern void nni_aio_get_sockaddr(nni_aio *aio, nng_sockaddr *);
+
// nni_aio_schedule indicates that the AIO has begun, and is scheduled for
// asychronous completion. This also starts the expiration timer. Note that
// prior to this, the aio is uncancellable. If the operation has a zero
diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h
index abf47f49..07fe44f5 100644
--- a/src/core/nng_impl.h
+++ b/src/core/nng_impl.h
@@ -42,6 +42,7 @@
#include "core/random.h"
#include "core/reap.h"
#include "core/stats.h"
+#include "core/stream.h"
#include "core/strs.h"
#include "core/taskq.h"
#include "core/thread.h"
diff --git a/src/core/options.c b/src/core/options.c
index 0b15d6e2..82735369 100644
--- a/src/core/options.c
+++ b/src/core/options.c
@@ -398,4 +398,20 @@ nni_setopt(const nni_option *opts, const char *nm, void *arg, const void *buf,
opts++;
}
return (NNG_ENOTSUP);
+}
+
+int
+nni_chkopt(const nni_chkoption *opts, const char *nm, const void *buf,
+ size_t sz, nni_type t)
+{
+ while (opts->o_name != NULL) {
+ if (strcmp(opts->o_name, nm) == 0) {
+ if (opts->o_check == NULL) {
+ return (NNG_EREADONLY);
+ }
+ return (opts->o_check(buf, sz, t));
+ }
+ opts++;
+ }
+ return (NNG_ENOTSUP);
} \ No newline at end of file
diff --git a/src/core/options.h b/src/core/options.h
index 9c5d4817..7b66dbfb 100644
--- a/src/core/options.h
+++ b/src/core/options.h
@@ -74,11 +74,20 @@ struct nni_option_s {
int (*o_set)(void *, const void *, size_t, nni_type);
};
+typedef struct nni_chkoption_s nni_chkoption;
+struct nni_chkoption_s {
+ const char *o_name;
+ // o_check can be NULL for read-only options
+ int (*o_check)(const void *, size_t, nni_type);
+};
+
// nni_getopt and nni_setopt are helper functions to implement options
// based on arrays of nni_option structures.
extern int nni_getopt(
const nni_option *, const char *, void *, void *, size_t *, nni_type);
extern int nni_setopt(
const nni_option *, const char *, void *, const void *, size_t, nni_type);
+extern int nni_chkopt(
+ const nni_chkoption *, const char *, const void *, size_t, nni_type);
#endif // CORE_OPTIONS_H
diff --git a/src/core/platform.h b/src/core/platform.h
index 69fa5db6..e415b438 100644
--- a/src/core/platform.h
+++ b/src/core/platform.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 2018 Devolutions <info@devolutions.net>
//
@@ -228,53 +228,6 @@ typedef struct nni_tcp_conn nni_tcp_conn;
typedef struct nni_tcp_dialer nni_tcp_dialer;
typedef struct nni_tcp_listener nni_tcp_listener;
-extern void nni_tcp_conn_fini(nni_tcp_conn *);
-
-// nni_tcp_conn_close closes the connection, which might actually be
-// implemented as a shutdown() call.
-// Further operations on it should return NNG_ECLOSED.
-extern void nni_tcp_conn_close(nni_tcp_conn *);
-
-// nni_tcp_conn_send sends data in the iov buffers to the peer.
-// The platform may modify the iovs.
-extern void nni_tcp_conn_send(nni_tcp_conn *, nni_aio *);
-
-// nni_tcp_conn_recv receives data into the buffers provided by the
-// I/O vector (iovs). The platform should attempt to scatter the received
-// data into the iovs if possible.
-//
-// It is possible for the reader to return less data than is requested,
-// in which case the caller is responsible for resubmitting. The platform
-// must not return "zero" data however. (It is an error to attempt to
-// receive zero bytes.) The platform may modify the iovs.
-extern void nni_tcp_conn_recv(nni_tcp_conn *, nni_aio *);
-
-// nni_tcp_conn_peername gets the peer name.
-extern int nni_tcp_conn_peername(nni_tcp_conn *, nni_sockaddr *);
-
-// nni_tcp_conn_sockname gets the local name.
-extern int nni_tcp_conn_sockname(nni_tcp_conn *, nni_sockaddr *);
-
-// nni_tcp_conn_set_nodelay indicates that the TCP pipe should send
-// data immediately, without any buffering. (Disable Nagle's algorithm.)
-extern int nni_tcp_conn_set_nodelay(nni_tcp_conn *, bool);
-
-// nni_tcp_conn_set_keepalive indicates that the TCP pipe should send
-// keepalive probes. Tuning of these keepalives is currently unsupported.
-extern int nni_tcp_conn_set_keepalive(nni_tcp_conn *, bool);
-
-// nni_tcp_conn_setopt is like setsockopt, but uses string names. These
-// are the same names from the TCP transport, generally. Examples are
-// NNG_OPT_TCP_NODELAY and NNG_OPT_TCP_KEEPALIVE.
-extern int nni_tcp_conn_setopt(
- nni_tcp_conn *, const char *, const void *, size_t, nni_type);
-
-// nni_tcp_conn_getopt is like getsockopt, but uses string names.
-// We support NNG_OPT_REMADDR and NNG_OPT_LOCADDR (with argument type
-// nng_sockaddr), and NNG_OPT_TCP_NODELAY and NNG_OPT_TCP_KEEPALIVE.
-extern int nni_tcp_conn_getopt(
- nni_tcp_conn *, const char *, void *, size_t *, nni_type);
-
// nni_tcp_dialer_init creates a new dialer object.
extern int nni_tcp_dialer_init(nni_tcp_dialer **);
@@ -287,11 +240,10 @@ extern void nni_tcp_dialer_fini(nni_tcp_dialer *);
// connection will be aborted.
extern void nni_tcp_dialer_close(nni_tcp_dialer *);
-// nni_tcp_dialer_dial attempts to create an outgoing connection,
-// asynchronously, to the address specified. On success, the first (and only)
+// nni_tcp_dial attempts to create an outgoing connection,
+// asynchronously, to the address in the aio. On success, the first (and only)
// output will be an nni_tcp_conn * associated with the remote server.
-extern void nni_tcp_dialer_dial(
- nni_tcp_dialer *, const nni_sockaddr *, nni_aio *);
+extern void nni_tcp_dial(nni_tcp_dialer *, nni_aio *);
// nni_tcp_dialer_getopt gets an option from the dialer.
extern int nni_tcp_dialer_setopt(
@@ -361,101 +313,12 @@ typedef struct nni_ipc_conn nni_ipc_conn;
typedef struct nni_ipc_dialer nni_ipc_dialer;
typedef struct nni_ipc_listener nni_ipc_listener;
-// nni_ipc_conn_fini disposes of the connection.
-extern void nni_ipc_conn_fini(nni_ipc_conn *);
-
-// nni_ipc_conn_close closes the connection, which might actually be
-// implemented as a shutdown() call.
-// Further operations on it should return NNG_ECLOSED.
-extern void nni_ipc_conn_close(nni_ipc_conn *);
-
-// nni_ipc_conn_send sends data in the iov buffers to the peer.
-// The platform may modify the iovs.
-extern void nni_ipc_conn_send(nni_ipc_conn *, nni_aio *);
-
-// nni_ipc_conn_recv receives data into the buffers provided by the
-// I/O vector (iovs). The platform should attempt to scatter the received
-// data into the iovs if possible.
-//
-// It is possible for the reader to return less data than is requested,
-// in which case the caller is responsible for resubmitting. The platform
-// must not return "zero" data however. (It is an error to attempt to
-// receive zero bytes.) The platform may modify the iovs.
-extern void nni_ipc_conn_recv(nni_ipc_conn *, nni_aio *);
-
-// nni_ipc_conn_setopt is like setsockopt, but uses string names. These
-// are the same names from the IPC transport, generally. There are no
-// options that are generally settable on an IPC connection.
-extern int nni_ipc_conn_setopt(
- nni_ipc_conn *, const char *, const void *, size_t, nni_type);
-
-// nni_ipc_conn_getopt is like getsockopt, but uses string names.
-// We support NNG_OPT_REMADDR and NNG_OPT_LOCADDR (with argument type
-// nng_sockaddr), and on some platforms NNG_OPT_IPC_PEER_[UID,GID,ZONEID]
-// (with type uint64_t.)
-extern int nni_ipc_conn_getopt(
- nni_ipc_conn *, const char *, void *, size_t *, nni_type);
-
-// nni_ipc_dialer_init creates a new dialer object.
-extern int nni_ipc_dialer_init(nni_ipc_dialer **);
-
-// nni_ipc_dialer_fini finalizes the dialer, closing it and freeing
-// all resources.
-extern void nni_ipc_dialer_fini(nni_ipc_dialer *);
-
-// nni_ipc_dialer_close closes the dialer.
-// Further operations on it should return NNG_ECLOSED. Any in-progress
-// connection will be aborted.
-extern void nni_ipc_dialer_close(nni_ipc_dialer *);
-
-// nni_ipc_dialer_dial attempts to create an outgoing connection,
-// asynchronously, to the address specified. On success, the first (and only)
-// output will be an nni_ipc_conn * associated with the remote server.
-extern void nni_ipc_dialer_dial(
- nni_ipc_dialer *, const nni_sockaddr *, nni_aio *);
-
-// nni_ipc_dialer_getopt is used to get options from the dialer.
-// At present there aren't any defined options.
-extern int nni_ipc_dialer_getopt(
- nni_ipc_dialer *, const char *, void *, size_t *, nni_type);
-
-// nni_ipc_dialer_setopt sets an option for the dialer. There aren't
-// any options defined at present.
-extern int nni_ipc_dialer_setopt(
- nni_ipc_dialer *, const char *, const void *, size_t, nni_type);
-
-// nni_ipc_listener_init creates a new listener object, unbound.
-extern int nni_ipc_listener_init(nni_ipc_listener **);
-
-// nni_ipc_listener_fini frees the listener and all associated resources.
-// It implictly closes the listener as well.
-extern void nni_ipc_listener_fini(nni_ipc_listener *);
-
-// nni_ipc_listener_close closes the listener. This will unbind
-// any bound socket, and further operations will result in NNG_ECLOSED.
-extern void nni_ipc_listener_close(nni_ipc_listener *);
-
-// nni_ipc_listener_listen creates the socket in listening mode, bound
-// to the specified address. Unlike TCP, this address does not change.
-extern int nni_ipc_listener_listen(nni_ipc_listener *, const nni_sockaddr *);
-
-// nni_ipc_listener_accept accepts in incoming connect, asynchronously.
-// On success, the first (and only) output will be an nni_ipc_conn *
-// associated with the remote peer.
-extern void nni_ipc_listener_accept(nni_ipc_listener *, nni_aio *);
-
-// nni_ipc_listener_getopt is used to get options from the listener.
-// The only valid option is NNG_OPT_LOCADDR, which will only have
-// a valid value if the socket is bound, otherwise the value returned
-// will be of type NNG_AF_UNSPEC.
-extern int nni_ipc_listener_getopt(
- nni_ipc_listener *, const char *, void *, size_t *, nni_type);
-
-// nni_ipc_listener_setopt sets an option for the listener. The only
-// valid options are NNG_OPT_IPC_SECURITY_DESCRIPTORS (Windows) and
-// NNG_OPT_IPC_PERMISSIONS (POSIX).
-extern int nni_ipc_listener_setopt(
- nni_ipc_listener *, const char *, const void *, size_t, nni_type);
+// IPC is so different from platform to platform. The following should
+// be implemented. If IPC isn't supported, all of these functions should
+// be stubs that just return NNG_ENOTSUP.
+extern int nni_ipc_dialer_alloc(nng_stream_dialer **, const nng_url *);
+extern int nni_ipc_listener_alloc(nng_stream_listener **, const nng_url *);
+extern int nni_ipc_checkopt(const char *, const void *, size_t, nni_type);
//
// UDP support. UDP is not connection oriented, and only has the notion
diff --git a/src/core/stream.c b/src/core/stream.c
new file mode 100644
index 00000000..52c5b1a6
--- /dev/null
+++ b/src/core/stream.c
@@ -0,0 +1,366 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+// This provides an abstraction for byte streams, allowing polymorphic
+// use of them in rather flexible contexts.
+
+#include <string.h>
+
+#include "core/nng_impl.h"
+#include <nng/supplemental/tls/tls.h>
+
+#include "core/tcp.h"
+#include "supplemental/tls/tls_api.h"
+#include "supplemental/websocket/websocket.h"
+
+static struct {
+ const char *scheme;
+ int (*dialer_alloc)(nng_stream_dialer **, const nng_url *);
+ int (*listener_alloc)(nng_stream_listener **, const nng_url *);
+ int (*checkopt)(const char *, const void *, size_t, nni_type);
+
+} stream_drivers[] = {
+ {
+ .scheme = "ipc",
+ .dialer_alloc = nni_ipc_dialer_alloc,
+ .listener_alloc = nni_ipc_listener_alloc,
+ .checkopt = nni_ipc_checkopt,
+ },
+ {
+ .scheme = "tcp",
+ .dialer_alloc = nni_tcp_dialer_alloc,
+ .listener_alloc = nni_tcp_listener_alloc,
+ .checkopt = nni_tcp_checkopt,
+ },
+ {
+ .scheme = "tcp4",
+ .dialer_alloc = nni_tcp_dialer_alloc,
+ .listener_alloc = nni_tcp_listener_alloc,
+ .checkopt = nni_tcp_checkopt,
+ },
+ {
+ .scheme = "tcp6",
+ .dialer_alloc = nni_tcp_dialer_alloc,
+ .listener_alloc = nni_tcp_listener_alloc,
+ .checkopt = nni_tcp_checkopt,
+ },
+ {
+ .scheme = "tls+tcp",
+ .dialer_alloc = nni_tls_dialer_alloc,
+ .listener_alloc = nni_tls_listener_alloc,
+ .checkopt = nni_tls_checkopt,
+ },
+ {
+ .scheme = "tls+tcp4",
+ .dialer_alloc = nni_tls_dialer_alloc,
+ .listener_alloc = nni_tls_listener_alloc,
+ .checkopt = nni_tls_checkopt,
+ },
+ {
+ .scheme = "tls+tcp6",
+ .dialer_alloc = nni_tls_dialer_alloc,
+ .listener_alloc = nni_tls_listener_alloc,
+ .checkopt = nni_tls_checkopt,
+ },
+ {
+ .scheme = "ws",
+ .dialer_alloc = nni_ws_dialer_alloc,
+ .listener_alloc = nni_ws_listener_alloc,
+ .checkopt = nni_ws_checkopt,
+ },
+ {
+ .scheme = "wss",
+ .dialer_alloc = nni_ws_dialer_alloc,
+ .listener_alloc = nni_ws_listener_alloc,
+ .checkopt = nni_ws_checkopt,
+ },
+ {
+ .scheme = NULL,
+ },
+};
+
+void
+nng_stream_close(nng_stream *s)
+{
+ s->s_close(s);
+}
+
+void
+nng_stream_free(nng_stream *s)
+{
+ if (s != NULL) {
+ s->s_free(s);
+ }
+}
+
+void
+nng_stream_send(nng_stream *s, nng_aio *aio)
+{
+ s->s_send(s, aio);
+}
+
+void
+nng_stream_recv(nng_stream *s, nng_aio *aio)
+{
+ s->s_recv(s, aio);
+}
+
+int
+nni_stream_getx(
+ nng_stream *s, const char *nm, void *data, size_t *szp, nni_type t)
+{
+ return (s->s_getx(s, nm, data, szp, t));
+}
+
+int
+nni_stream_setx(
+ nng_stream *s, const char *nm, const void *data, size_t sz, nni_type t)
+{
+ return (s->s_setx(s, nm, data, sz, t));
+}
+
+void
+nng_stream_dialer_close(nng_stream_dialer *d)
+{
+ d->sd_close(d);
+}
+
+void
+nng_stream_dialer_free(nng_stream_dialer *d)
+{
+ if (d != NULL) {
+ d->sd_free(d);
+ }
+}
+
+void
+nng_stream_dialer_dial(nng_stream_dialer *d, nng_aio *aio)
+{
+ d->sd_dial(d, aio);
+}
+
+int
+nng_stream_dialer_alloc_url(nng_stream_dialer **dp, const nng_url *url)
+{
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+
+ for (int i = 0; stream_drivers[i].scheme != NULL; i++) {
+ if (strcmp(stream_drivers[i].scheme, url->u_scheme) == 0) {
+ return (stream_drivers[i].dialer_alloc(dp, url));
+ }
+ }
+ return (NNG_ENOTSUP);
+}
+
+int
+nng_stream_dialer_alloc(nng_stream_dialer **dp, const char *uri)
+{
+ nng_url *url;
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+ if ((rv = nng_url_parse(&url, uri)) != 0) {
+ return (rv);
+ }
+ rv = nng_stream_dialer_alloc_url(dp, url);
+ nng_url_free(url);
+ return (rv);
+}
+
+int
+nni_stream_dialer_getx(
+ nng_stream_dialer *d, const char *nm, void *data, size_t *szp, nni_type t)
+{
+ return (d->sd_getx(d, nm, data, szp, t));
+}
+
+int
+nni_stream_dialer_setx(nng_stream_dialer *d, const char *nm, const void *data,
+ size_t sz, nni_type t)
+{
+ return (d->sd_setx(d, nm, data, sz, t));
+}
+
+void
+nng_stream_listener_close(nng_stream_listener *l)
+{
+ l->sl_close(l);
+}
+void
+nng_stream_listener_free(nng_stream_listener *l)
+{
+ if (l != NULL) {
+ l->sl_free(l);
+ }
+}
+int
+nng_stream_listener_listen(nng_stream_listener *l)
+{
+ return (l->sl_listen(l));
+}
+
+void
+nng_stream_listener_accept(nng_stream_listener *l, nng_aio *aio)
+{
+ l->sl_accept(l, aio);
+}
+
+int
+nni_stream_listener_getx(nng_stream_listener *l, const char *nm, void *data,
+ size_t *szp, nni_type t)
+{
+ return (l->sl_getx(l, nm, data, szp, t));
+}
+
+int
+nni_stream_listener_setx(nng_stream_listener *l, const char *nm,
+ const void *data, size_t sz, nni_type t)
+{
+ return (l->sl_setx(l, nm, data, sz, t));
+}
+
+int
+nng_stream_listener_alloc_url(nng_stream_listener **lp, const nng_url *url)
+{
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+
+ for (int i = 0; stream_drivers[i].scheme != NULL; i++) {
+ if (strcmp(stream_drivers[i].scheme, url->u_scheme) == 0) {
+ return (stream_drivers[i].listener_alloc(lp, url));
+ }
+ }
+ return (NNG_ENOTSUP);
+}
+
+int
+nng_stream_listener_alloc(nng_stream_listener **lp, const char *uri)
+{
+ nng_url *url;
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+
+ if ((rv = nng_url_parse(&url, uri)) != 0) {
+ return (rv);
+ }
+ rv = nng_stream_listener_alloc_url(lp, url);
+ nng_url_free(url);
+ return (rv);
+}
+
+int
+nni_stream_checkopt(const char *scheme, const char *name, const void *data,
+ size_t sz, nni_type t)
+{
+ for (int i = 0; stream_drivers[i].scheme != NULL; i++) {
+ if (strcmp(stream_drivers[i].scheme, scheme) != 0) {
+ continue;
+ }
+ if (stream_drivers[i].checkopt == NULL) {
+ return (NNG_ENOTSUP);
+ }
+ return (stream_drivers[i].checkopt(name, data, sz, t));
+ }
+ return (NNG_ENOTSUP);
+}
+
+//
+// This next block sets up to define the various typed option functions.
+// To make it easier to cover them all at once, we use macros.
+//
+
+#define DEFGET(base) \
+ int nng_##base##_get( \
+ nng_##base *s, const char *nm, void *vp, size_t *szp) \
+ { \
+ return (nni_##base##_getx(s, nm, vp, szp, NNI_TYPE_OPAQUE)); \
+ }
+
+#define DEFTYPEDGET(base, suffix, type, nnitype) \
+ int nng_##base##_get_##suffix( \
+ nng_##base *s, const char *nm, type *vp) \
+ { \
+ size_t sz = sizeof(*vp); \
+ return (nni_##base##_getx(s, nm, vp, &sz, nnitype)); \
+ }
+
+#define DEFGETALL(base) \
+ DEFGET(base) \
+ DEFTYPEDGET(base, int, int, NNI_TYPE_INT32) \
+ DEFTYPEDGET(base, bool, bool, NNI_TYPE_BOOL) \
+ DEFTYPEDGET(base, size, size_t, NNI_TYPE_SIZE) \
+ DEFTYPEDGET(base, uint64, uint64_t, NNI_TYPE_UINT64) \
+ DEFTYPEDGET(base, ptr, void *, NNI_TYPE_POINTER) \
+ DEFTYPEDGET(base, ms, nng_duration, NNI_TYPE_DURATION) \
+ DEFTYPEDGET(base, addr, nng_sockaddr, NNI_TYPE_SOCKADDR)
+
+DEFGETALL(stream)
+DEFGETALL(stream_dialer)
+DEFGETALL(stream_listener)
+
+#define DEFSET(base) \
+ int nng_##base##_set( \
+ nng_##base *s, const char *nm, const void *vp, size_t sz) \
+ { \
+ return (nni_##base##_setx(s, nm, vp, sz, NNI_TYPE_OPAQUE)); \
+ }
+
+#define DEFTYPEDSETEX(base, suffix, type, len, nnitype) \
+ int nng_##base##_set_##suffix(nng_##base *s, const char *nm, type v) \
+ { \
+ return (nni_##base##_setx(s, nm, &v, len, nnitype)); \
+ }
+
+#define DEFTYPEDSET(base, suffix, type, nnitype) \
+ int nng_##base##_set_##suffix(nng_##base *s, const char *nm, type v) \
+ { \
+ return (nni_##base##_setx(s, nm, &v, sizeof(v), nnitype)); \
+ }
+
+#define DEFSTRINGSET(base) \
+ int nng_##base##_set_string( \
+ nng_##base *s, const char *nm, const char *v) \
+ { \
+ return (nni_##base##_setx(s, nm, v, \
+ v != NULL ? strlen(v) + 1 : 0, NNI_TYPE_STRING)); \
+ }
+
+#define DEFSOCKADDRSET(base) \
+ int nng_##base##_set_adddr( \
+ nng_##base *s, const char *nm, const nng_sockaddr *v) \
+ { \
+ return (nni_##base##_setx( \
+ s, nm, v, sizeof(*v), NNI_TYPE_SOCKADDR)); \
+ }
+
+#define DEFSETALL(base) \
+ DEFSET(base) \
+ DEFTYPEDSET(base, int, int, NNI_TYPE_INT32) \
+ DEFTYPEDSET(base, bool, bool, NNI_TYPE_BOOL) \
+ DEFTYPEDSET(base, size, size_t, NNI_TYPE_SIZE) \
+ DEFTYPEDSET(base, ms, nng_duration, NNI_TYPE_DURATION) \
+ DEFTYPEDSET(base, ptr, void *, NNI_TYPE_POINTER) \
+ DEFSTRINGSET(base) \
+ DEFSOCKADDRSET(base)
+
+DEFSETALL(stream)
+DEFSETALL(stream_dialer)
+DEFSETALL(stream_listener) \ No newline at end of file
diff --git a/src/core/stream.h b/src/core/stream.h
new file mode 100644
index 00000000..18914979
--- /dev/null
+++ b/src/core/stream.h
@@ -0,0 +1,69 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef CORE_STREAM_H
+#define CORE_STREAM_H
+
+// This provides an abstraction for byte streams, allowing polymorphic
+// use of them in rather flexible contexts.
+
+#include "core/nng_impl.h"
+
+// Private property operations (these include the types.)
+extern int nni_stream_getx(
+ nng_stream *, const char *, void *, size_t *, nni_type);
+extern int nni_stream_setx(
+ nng_stream *, const char *, const void *, size_t, nni_type);
+
+extern int nni_stream_dialer_getx(
+ nng_stream_dialer *, const char *, void *, size_t *, nni_type);
+extern int nni_stream_dialer_setx(
+ nng_stream_dialer *, const char *, const void *, size_t, nni_type);
+
+extern int nni_stream_listener_getx(
+ nng_stream_listener *, const char *, void *, size_t *, nni_type);
+extern int nni_stream_listener_setx(
+ nng_stream_listener *, const char *, const void *, size_t, nni_type);
+
+extern int nni_stream_checkopt(
+ const char *, const char *, const void *, size_t, nni_type);
+
+// This is the common implementation of a connected byte stream. It should be
+// the first element of any implementation. Applications are not permitted to
+// access it directly.
+struct nng_stream {
+ void (*s_free)(void *);
+ void (*s_close)(void *);
+ void (*s_recv)(void *, nng_aio *);
+ void (*s_send)(void *, nng_aio *);
+ int (*s_getx)(void *, const char *, void *, size_t *, nni_type);
+ int (*s_setx)(void *, const char *, const void *, size_t, nni_type);
+};
+
+// Dialer implementation. Stream dialers create streams.
+struct nng_stream_dialer {
+ void (*sd_free)(void *);
+ void (*sd_close)(void *);
+ void (*sd_dial)(void *, nng_aio *);
+ int (*sd_getx)(void *, const char *, void *, size_t *, nni_type);
+ int (*sd_setx)(void *, const char *, const void *, size_t, nni_type);
+};
+
+// Listener implementation. Stream listeners accept connections and create
+// streams.
+struct nng_stream_listener {
+ void (*sl_free)(void *);
+ void (*sl_close)(void *);
+ int (*sl_listen)(void *);
+ void (*sl_accept)(void *, nng_aio *);
+ int (*sl_getx)(void *, const char *, void *, size_t *, nni_type);
+ int (*sl_setx)(void *, const char *, const void *, size_t, nni_type);
+};
+
+#endif // CORE_STREAM_H
diff --git a/src/core/tcp.h b/src/core/tcp.h
new file mode 100644
index 00000000..ac4398d0
--- /dev/null
+++ b/src/core/tcp.h
@@ -0,0 +1,24 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef CORE_TCP_H
+#define CORE_TCP_H
+
+#include "core/nng_impl.h"
+
+// These are interfaces we use for TCP internally. These are not exposed
+// to the public API.
+
+extern int nni_tcp_dialer_alloc(nng_stream_dialer **, const nng_url *);
+extern int nni_tcp_listener_alloc(nng_stream_listener **, const nng_url *);
+
+// nni_tcp_checkopt is used to validate (generically) options.
+extern int nni_tcp_checkopt(const char *, const void *, size_t, nni_type);
+
+#endif // CORE_TCP_H
diff --git a/src/core/transport.c b/src/core/transport.c
index 54c4bcfe..071ea0c7 100644
--- a/src/core/transport.c
+++ b/src/core/transport.c
@@ -1,6 +1,7 @@
//
-// 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>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -122,6 +123,16 @@ nni_tran_chkopt(const char *name, const void *v, size_t sz, int typ)
const nni_tran_listener_ops *lops;
const nni_option * o;
+ // Check option entry point is cleaner than endpoint hacks.
+ if (t->t_tran.tran_checkopt != NULL) {
+ rv = t->t_tran.tran_checkopt(name, v, sz, typ);
+ if (rv != NNG_ENOTSUP) {
+ nni_mtx_unlock(&nni_tran_lk);
+ return (rv);
+ }
+ continue;
+ }
+
// Generally we look for endpoint options. We check both
// dialers and listeners.
dops = t->t_tran.tran_dialer;
diff --git a/src/core/transport.h b/src/core/transport.h
index f3d252c4..84d9c1d9 100644
--- a/src/core/transport.h
+++ b/src/core/transport.h
@@ -183,6 +183,12 @@ struct nni_tran {
// tran_fini, if not NULL, is called during library deinitialization.
// It should release any global resources, close any open files, etc.
void (*tran_fini)(void);
+
+ // tran_chkopt is used to check option validity; this is used as
+ // an initial filter on the data, without actually setting anything.
+ // This can be useful, for example, before any transports are
+ // configured on the socket.
+ int (*tran_checkopt)(const char *, const void *, size_t, nni_type);
};
// These APIs are used by the framework internally, and not for use by
diff --git a/src/core/url.c b/src/core/url.c
index 5e2317ea..b2cf77f8 100644
--- a/src/core/url.c
+++ b/src/core/url.c
@@ -231,8 +231,21 @@ nni_url_default_port(const char *scheme)
const char *s;
for (int i = 0; (s = nni_url_default_ports[i].scheme) != NULL; i++) {
- if (strcmp(s, scheme) == 0) {
+ size_t l = strlen(s);
+ if (strncmp(s, scheme, strlen(s)) != 0) {
+ continue;
+ }
+ // It can have a suffix of either "4" or "6" to restrict
+ // the address family. This is an NNG extension.
+ switch (scheme[l]) {
+ case '\0':
return (nni_url_default_ports[i].port);
+ case '4':
+ case '6':
+ if (scheme[l + 1] == '\0') {
+ return (nni_url_default_ports[i].port);
+ }
+ break;
}
}
return ("");
@@ -463,19 +476,23 @@ error:
void
nni_url_free(nni_url *url)
{
- nni_strfree(url->u_rawurl);
- nni_strfree(url->u_scheme);
- nni_strfree(url->u_userinfo);
- nni_strfree(url->u_host);
- nni_strfree(url->u_hostname);
- nni_strfree(url->u_port);
- nni_strfree(url->u_path);
- nni_strfree(url->u_query);
- nni_strfree(url->u_fragment);
- nni_strfree(url->u_requri);
- NNI_FREE_STRUCT(url);
+ if (url != NULL) {
+ nni_strfree(url->u_rawurl);
+ nni_strfree(url->u_scheme);
+ nni_strfree(url->u_userinfo);
+ nni_strfree(url->u_host);
+ nni_strfree(url->u_hostname);
+ nni_strfree(url->u_port);
+ nni_strfree(url->u_path);
+ nni_strfree(url->u_query);
+ nni_strfree(url->u_fragment);
+ nni_strfree(url->u_requri);
+ NNI_FREE_STRUCT(url);
+ }
}
+#define URL_COPYSTR(d, s) ((s != NULL) && ((d = nni_strdup(s)) == NULL))
+
int
nni_url_clone(nni_url **dstp, const nni_url *src)
{
@@ -484,7 +501,6 @@ nni_url_clone(nni_url **dstp, const nni_url *src)
if ((dst = NNI_ALLOC_STRUCT(dst)) == NULL) {
return (NNG_ENOMEM);
}
-#define URL_COPYSTR(d, s) ((s != NULL) && ((d = nni_strdup(s)) == NULL))
if (URL_COPYSTR(dst->u_rawurl, src->u_rawurl) ||
URL_COPYSTR(dst->u_scheme, src->u_scheme) ||
URL_COPYSTR(dst->u_userinfo, src->u_userinfo) ||
@@ -498,7 +514,8 @@ nni_url_clone(nni_url **dstp, const nni_url *src)
nni_url_free(dst);
return (NNG_ENOMEM);
}
-#undef URL_COPYSTR
*dstp = dst;
return (0);
}
+
+#undef URL_COPYSTR
diff --git a/src/core/url.h b/src/core/url.h
index b96401bd..2358f6ba 100644
--- a/src/core/url.h
+++ b/src/core/url.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>
//
// This software is supplied under the terms of the MIT License, a
diff --git a/src/platform/posix/posix_ipc.h b/src/platform/posix/posix_ipc.h
index bbe11f0d..f570b172 100644
--- a/src/platform/posix/posix_ipc.h
+++ b/src/platform/posix/posix_ipc.h
@@ -1,7 +1,7 @@
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2018 Devolutions <info@devolutions.net>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -10,6 +10,7 @@
//
#include "core/nng_impl.h"
+#include "core/stream.h"
#ifdef NNG_PLATFORM_POSIX
#include "platform/posix/posix_aio.h"
@@ -17,6 +18,7 @@
#include <sys/types.h> // For mode_t
struct nni_ipc_conn {
+ nng_stream stream;
nni_posix_pfd * pfd;
nni_list readq;
nni_list writeq;
@@ -24,27 +26,17 @@ struct nni_ipc_conn {
nni_mtx mtx;
nni_aio * dial_aio;
nni_ipc_dialer *dialer;
- nni_reap_item reap;
};
struct nni_ipc_dialer {
- nni_list connq; // pending connections
- bool closed;
- nni_mtx mtx;
+ nng_stream_dialer sd;
+ nni_list connq; // pending connections
+ bool closed;
+ nni_mtx mtx;
+ nng_sockaddr sa;
};
-struct nni_ipc_listener {
- nni_posix_pfd *pfd;
- nng_sockaddr sa;
- nni_list acceptq;
- bool started;
- bool closed;
- char * path;
- mode_t perms;
- nni_mtx mtx;
-};
-
-extern int nni_posix_ipc_conn_init(nni_ipc_conn **, nni_posix_pfd *);
-extern void nni_posix_ipc_conn_start(nni_ipc_conn *);
+extern int nni_posix_ipc_init(nni_ipc_conn **, nni_posix_pfd *);
+extern void nni_posix_ipc_start(nni_ipc_conn *);
#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/posix/posix_ipcconn.c b/src/platform/posix/posix_ipcconn.c
index 48bd75a4..07ec6213 100644
--- a/src/platform/posix/posix_ipcconn.c
+++ b/src/platform/posix/posix_ipcconn.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -39,8 +39,10 @@
#include "posix_ipc.h"
+typedef struct nni_ipc_conn ipc_conn;
+
static void
-ipc_conn_dowrite(nni_ipc_conn *c)
+ipc_dowrite(ipc_conn *c)
{
nni_aio *aio;
int fd;
@@ -122,7 +124,7 @@ ipc_conn_dowrite(nni_ipc_conn *c)
}
static void
-ipc_conn_doread(nni_ipc_conn *c)
+ipc_doread(ipc_conn *c)
{
nni_aio *aio;
int fd;
@@ -199,9 +201,10 @@ ipc_conn_doread(nni_ipc_conn *c)
}
}
-void
-nni_ipc_conn_close(nni_ipc_conn *c)
+static void
+ipc_close(void *arg)
{
+ ipc_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (!c->closed) {
nni_aio *aio;
@@ -217,20 +220,20 @@ nni_ipc_conn_close(nni_ipc_conn *c)
}
static void
-ipc_conn_cb(nni_posix_pfd *pfd, int events, void *arg)
+ipc_cb(nni_posix_pfd *pfd, int events, void *arg)
{
- nni_ipc_conn *c = arg;
+ ipc_conn *c = arg;
if (events & (POLLHUP | POLLERR | POLLNVAL)) {
- nni_ipc_conn_close(c);
+ ipc_close(c);
return;
}
nni_mtx_lock(&c->mtx);
if (events & POLLIN) {
- ipc_conn_doread(c);
+ ipc_doread(c);
}
if (events & POLLOUT) {
- ipc_conn_dowrite(c);
+ ipc_dowrite(c);
}
events = 0;
if (!nni_list_empty(&c->writeq)) {
@@ -246,9 +249,9 @@ ipc_conn_cb(nni_posix_pfd *pfd, int events, void *arg)
}
static void
-ipc_conn_cancel(nni_aio *aio, void *arg, int rv)
+ipc_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_conn *c = arg;
+ ipc_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (nni_aio_list_active(aio)) {
@@ -258,18 +261,18 @@ ipc_conn_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_ipc_conn_send(nni_ipc_conn *c, nni_aio *aio)
+static void
+ipc_send(void *arg, nni_aio *aio)
{
-
- int rv;
+ ipc_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
}
nni_mtx_lock(&c->mtx);
- if ((rv = nni_aio_schedule(aio, ipc_conn_cancel, c)) != 0) {
+ if ((rv = nni_aio_schedule(aio, ipc_cancel, c)) != 0) {
nni_mtx_unlock(&c->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -277,7 +280,7 @@ nni_ipc_conn_send(nni_ipc_conn *c, nni_aio *aio)
nni_aio_list_append(&c->writeq, aio);
if (nni_list_first(&c->writeq) == aio) {
- ipc_conn_dowrite(c);
+ ipc_dowrite(c);
// If we are still the first thing on the list, that
// means we didn't finish the job, so arm the poller to
// complete us.
@@ -288,17 +291,18 @@ nni_ipc_conn_send(nni_ipc_conn *c, nni_aio *aio)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_ipc_conn_recv(nni_ipc_conn *c, nni_aio *aio)
+static void
+ipc_recv(void *arg, nni_aio *aio)
{
- int rv;
+ ipc_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
}
nni_mtx_lock(&c->mtx);
- if ((rv = nni_aio_schedule(aio, ipc_conn_cancel, c)) != 0) {
+ if ((rv = nni_aio_schedule(aio, ipc_cancel, c)) != 0) {
nni_mtx_unlock(&c->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -310,7 +314,7 @@ nni_ipc_conn_recv(nni_ipc_conn *c, nni_aio *aio)
// many cases. We also need not arm a list if it was already
// armed.
if (nni_list_first(&c->readq) == aio) {
- ipc_conn_doread(c);
+ ipc_doread(c);
// If we are still the first thing on the list, that
// means we didn't finish the job, so arm the poller to
// complete us.
@@ -322,8 +326,8 @@ nni_ipc_conn_recv(nni_ipc_conn *c, nni_aio *aio)
}
static int
-ipc_conn_peerid(nni_ipc_conn *c, uint64_t *euid, uint64_t *egid,
- uint64_t *prid, uint64_t *znid)
+ipc_peerid(ipc_conn *c, uint64_t *euid, uint64_t *egid, uint64_t *prid,
+ uint64_t *znid)
{
int fd = nni_posix_pfd_fd(c->pfd);
#if defined(NNG_HAVE_GETPEEREID)
@@ -403,43 +407,43 @@ ipc_conn_peerid(nni_ipc_conn *c, uint64_t *euid, uint64_t *egid,
#endif
}
-int
-ipc_conn_get_peer_uid(void *arg, void *buf, size_t *szp, nni_type t)
+static int
+ipc_get_peer_uid(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_conn *c = arg;
- int rv;
- uint64_t ignore;
- uint64_t id;
+ ipc_conn *c = arg;
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
- if ((rv = ipc_conn_peerid(c, &id, &ignore, &ignore, &ignore)) != 0) {
+ if ((rv = ipc_peerid(c, &id, &ignore, &ignore, &ignore)) != 0) {
return (rv);
}
return (nni_copyout_u64(id, buf, szp, t));
}
static int
-ipc_conn_get_peer_gid(void *arg, void *buf, size_t *szp, nni_type t)
+ipc_get_peer_gid(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_conn *c = arg;
- int rv;
- uint64_t ignore;
- uint64_t id;
+ ipc_conn *c = arg;
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
- if ((rv = ipc_conn_peerid(c, &ignore, &id, &ignore, &ignore)) != 0) {
+ if ((rv = ipc_peerid(c, &ignore, &id, &ignore, &ignore)) != 0) {
return (rv);
}
return (nni_copyout_u64(id, buf, szp, t));
}
static int
-ipc_conn_get_peer_zoneid(void *arg, void *buf, size_t *szp, nni_type t)
+ipc_get_peer_zoneid(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_conn *c = arg;
- int rv;
- uint64_t ignore;
- uint64_t id;
+ ipc_conn *c = arg;
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
- if ((rv = ipc_conn_peerid(c, &ignore, &ignore, &ignore, &id)) != 0) {
+ if ((rv = ipc_peerid(c, &ignore, &ignore, &ignore, &id)) != 0) {
return (rv);
}
if (id == (uint64_t) -1) {
@@ -450,14 +454,14 @@ ipc_conn_get_peer_zoneid(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-ipc_conn_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type t)
+ipc_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_conn *c = arg;
- int rv;
- uint64_t ignore;
- uint64_t id;
+ ipc_conn *c = arg;
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
- if ((rv = ipc_conn_peerid(c, &ignore, &ignore, &id, &ignore)) != 0) {
+ if ((rv = ipc_peerid(c, &ignore, &ignore, &id, &ignore)) != 0) {
return (rv);
}
if (id == (uint64_t) -1) {
@@ -468,9 +472,9 @@ ipc_conn_get_peer_pid(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-ipc_conn_get_addr(void *arg, void *buf, size_t *szp, nni_type t)
+ipc_get_addr(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_conn * c = arg;
+ ipc_conn * c = arg;
nni_sockaddr sa;
struct sockaddr_storage ss;
socklen_t sslen = sizeof(ss);
@@ -486,36 +490,17 @@ ipc_conn_get_addr(void *arg, void *buf, size_t *szp, nni_type t)
return (nni_copyout_sockaddr(&sa, buf, szp, t));
}
-int
-nni_posix_ipc_conn_init(nni_ipc_conn **cp, nni_posix_pfd *pfd)
-{
- nni_ipc_conn *c;
-
- if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
- return (NNG_ENOMEM);
- }
-
- c->closed = false;
- c->pfd = pfd;
-
- nni_mtx_init(&c->mtx);
- nni_aio_list_init(&c->readq);
- nni_aio_list_init(&c->writeq);
-
- *cp = c;
- return (0);
-}
-
void
-nni_posix_ipc_conn_start(nni_ipc_conn *c)
+nni_posix_ipc_start(nni_ipc_conn *c)
{
- nni_posix_pfd_set_cb(c->pfd, ipc_conn_cb, c);
+ nni_posix_pfd_set_cb(c->pfd, ipc_cb, c);
}
-void
-nni_ipc_conn_fini(nni_ipc_conn *c)
+static void
+ipc_free(void *arg)
{
- nni_ipc_conn_close(c);
+ ipc_conn *c = arg;
+ ipc_close(c);
nni_posix_pfd_fini(c->pfd);
nni_mtx_lock(&c->mtx); // not strictly needed, but shut up TSAN
c->pfd = NULL;
@@ -525,46 +510,72 @@ nni_ipc_conn_fini(nni_ipc_conn *c)
NNI_FREE_STRUCT(c);
}
-static const nni_option ipc_conn_options[] = {
+static const nni_option ipc_options[] = {
{
.o_name = NNG_OPT_LOCADDR,
- .o_get = ipc_conn_get_addr,
+ .o_get = ipc_get_addr,
},
{
.o_name = NNG_OPT_REMADDR,
- .o_get = ipc_conn_get_addr,
+ .o_get = ipc_get_addr,
},
{
.o_name = NNG_OPT_IPC_PEER_PID,
- .o_get = ipc_conn_get_peer_pid,
+ .o_get = ipc_get_peer_pid,
},
{
.o_name = NNG_OPT_IPC_PEER_UID,
- .o_get = ipc_conn_get_peer_uid,
+ .o_get = ipc_get_peer_uid,
},
{
.o_name = NNG_OPT_IPC_PEER_GID,
- .o_get = ipc_conn_get_peer_gid,
+ .o_get = ipc_get_peer_gid,
},
{
.o_name = NNG_OPT_IPC_PEER_ZONEID,
- .o_get = ipc_conn_get_peer_zoneid,
+ .o_get = ipc_get_peer_zoneid,
},
{
.o_name = NULL,
},
};
-int
-nni_ipc_conn_getopt(
- nni_ipc_conn *c, const char *name, void *val, size_t *szp, nni_type t)
+static int
+ipc_getx(void *arg, const char *name, void *val, size_t *szp, nni_type t)
{
- return (nni_getopt(ipc_conn_options, name, c, val, szp, t));
+ ipc_conn *c = arg;
+ return (nni_getopt(ipc_options, name, c, val, szp, t));
+}
+
+static int
+ipc_setx(void *arg, const char *name, const void *val, size_t sz, nni_type t)
+{
+ ipc_conn *c = arg;
+ return (nni_setopt(ipc_options, name, c, val, sz, t));
}
int
-nni_ipc_conn_setopt(
- nni_ipc_conn *c, const char *name, const void *val, size_t sz, nni_type t)
+nni_posix_ipc_init(nni_ipc_conn **cp, nni_posix_pfd *pfd)
{
- return (nni_setopt(ipc_conn_options, name, c, val, sz, t));
-} \ No newline at end of file
+ ipc_conn *c;
+
+ if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ c->closed = false;
+ c->pfd = pfd;
+ c->stream.s_free = ipc_free;
+ c->stream.s_close = ipc_close;
+ c->stream.s_send = ipc_send;
+ c->stream.s_recv = ipc_recv;
+ c->stream.s_getx = ipc_getx;
+ c->stream.s_setx = ipc_setx;
+
+ nni_mtx_init(&c->mtx);
+ nni_aio_list_init(&c->readq);
+ nni_aio_list_init(&c->writeq);
+
+ *cp = c;
+ return (0);
+}
diff --git a/src/platform/posix/posix_ipcdial.c b/src/platform/posix/posix_ipcdial.c
index d3dc2109..3182b390 100644
--- a/src/platform/posix/posix_ipcdial.c
+++ b/src/platform/posix/posix_ipcdial.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -29,25 +29,13 @@
#include "posix_ipc.h"
-// Dialer stuff.
-int
-nni_ipc_dialer_init(nni_ipc_dialer **dp)
-{
- nni_ipc_dialer *d;
+typedef struct nni_ipc_dialer ipc_dialer;
- if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
- return (NNG_ENOMEM);
- }
- nni_mtx_init(&d->mtx);
- d->closed = false;
- nni_aio_list_init(&d->connq);
- *dp = d;
- return (0);
-}
-
-void
-nni_ipc_dialer_close(nni_ipc_dialer *d)
+// Dialer stuff.
+static void
+ipc_dialer_close(void *arg)
{
+ ipc_dialer *d = arg;
nni_mtx_lock(&d->mtx);
if (!d->closed) {
nni_aio *aio;
@@ -58,9 +46,8 @@ nni_ipc_dialer_close(nni_ipc_dialer *d)
if ((c = nni_aio_get_prov_extra(aio, 0)) != NULL) {
c->dial_aio = NULL;
nni_aio_set_prov_extra(aio, 0, NULL);
- nni_ipc_conn_close(c);
- nni_reap(
- &c->reap, (nni_cb) nni_ipc_conn_fini, c);
+ nng_stream_close(&c->stream);
+ nng_stream_free(&c->stream);
}
nni_aio_finish_error(aio, NNG_ECLOSED);
}
@@ -68,10 +55,11 @@ nni_ipc_dialer_close(nni_ipc_dialer *d)
nni_mtx_unlock(&d->mtx);
}
-void
-nni_ipc_dialer_fini(nni_ipc_dialer *d)
+static void
+ipc_dialer_free(void *arg)
{
- nni_ipc_dialer_close(d);
+ ipc_dialer *d = arg;
+ ipc_dialer_close(d);
nni_mtx_fini(&d->mtx);
NNI_FREE_STRUCT(d);
}
@@ -94,7 +82,7 @@ ipc_dialer_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&d->mtx);
nni_aio_finish_error(aio, rv);
- nni_ipc_conn_fini(c);
+ nng_stream_free(&c->stream);
}
static void
@@ -137,13 +125,13 @@ ipc_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg)
nni_mtx_unlock(&d->mtx);
if (rv != 0) {
- nni_ipc_conn_close(c);
- nni_ipc_conn_fini(c);
+ nng_stream_close(&c->stream);
+ nng_stream_free(&c->stream);
nni_aio_finish_error(aio, rv);
return;
}
- nni_posix_ipc_conn_start(c);
+ nni_posix_ipc_start(c);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
@@ -151,8 +139,9 @@ ipc_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg)
// We don't give local address binding support. Outbound dialers always
// get an ephemeral port.
void
-nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
+ipc_dialer_dial(void *arg, nni_aio *aio)
{
+ ipc_dialer * d = arg;
nni_ipc_conn * c;
nni_posix_pfd * pfd = NULL;
struct sockaddr_storage ss;
@@ -164,7 +153,7 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
return;
}
- if (((sslen = nni_posix_nn2sockaddr(&ss, sa)) == 0) ||
+ if (((sslen = nni_posix_nn2sockaddr(&ss, &d->sa)) == 0) ||
(ss.ss_family != AF_UNIX)) {
nni_aio_finish_error(aio, NNG_EADDRINVAL);
return;
@@ -182,7 +171,7 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_aio_finish_error(aio, rv);
return;
}
- if ((rv = nni_posix_ipc_conn_init(&c, pfd)) != 0) {
+ if ((rv = nni_posix_ipc_init(&c, pfd)) != 0) {
nni_posix_pfd_fini(pfd);
nni_aio_finish_error(aio, rv);
return;
@@ -222,7 +211,7 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
// on loopback, and probably not on every platform.
nni_aio_set_prov_extra(aio, 0, NULL);
nni_mtx_unlock(&d->mtx);
- nni_posix_ipc_conn_start(c);
+ nni_posix_ipc_start(c);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
return;
@@ -230,7 +219,7 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
error:
nni_aio_set_prov_extra(aio, 0, NULL);
nni_mtx_unlock(&d->mtx);
- nni_reap(&c->reap, (nni_cb) nni_ipc_conn_fini, c);
+ nng_stream_free(&c->stream);
nni_aio_finish_error(aio, rv);
}
@@ -241,15 +230,44 @@ static const nni_option ipc_dialer_options[] = {
};
int
-nni_ipc_dialer_getopt(
- nni_ipc_dialer *d, const char *name, void *buf, size_t *szp, nni_type t)
+ipc_dialer_getx(void *arg, const char *nm, void *buf, size_t *szp, nni_type t)
+{
+ ipc_dialer *d = arg;
+ return (nni_getopt(ipc_dialer_options, nm, d, buf, szp, t));
+}
+
+int
+ipc_dialer_setx(
+ void *arg, const char *nm, const void *buf, size_t sz, nni_type t)
{
- return (nni_getopt(ipc_dialer_options, name, d, buf, szp, t));
+ ipc_dialer *d = arg;
+ return (nni_setopt(ipc_dialer_options, nm, d, buf, sz, t));
}
int
-nni_ipc_dialer_setopt(nni_ipc_dialer *d, const char *name, const void *buf,
- size_t sz, nni_type t)
+nni_ipc_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
{
- return (nni_setopt(ipc_dialer_options, name, d, buf, sz, t));
-} \ No newline at end of file
+ ipc_dialer *d;
+
+ if ((strcmp(url->u_scheme, "ipc") != 0) || (url->u_path == NULL) ||
+ (strlen(url->u_path) == 0) ||
+ (strlen(url->u_path) >= NNG_MAXADDRLEN)) {
+ return (NNG_EADDRINVAL);
+ }
+ if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ nni_mtx_init(&d->mtx);
+ nni_aio_list_init(&d->connq);
+ d->closed = false;
+ d->sa.s_ipc.sa_family = NNG_AF_IPC;
+ strcpy(d->sa.s_ipc.sa_path, url->u_path);
+ d->sd.sd_free = ipc_dialer_free;
+ d->sd.sd_close = ipc_dialer_close;
+ d->sd.sd_dial = ipc_dialer_dial;
+ d->sd.sd_getx = ipc_dialer_getx;
+ d->sd.sd_setx = ipc_dialer_setx;
+
+ *dp = (void *) d;
+ return (0);
+}
diff --git a/src/platform/posix/posix_ipclisten.c b/src/platform/posix/posix_ipclisten.c
index 11b56ab0..2b5d0edd 100644
--- a/src/platform/posix/posix_ipclisten.c
+++ b/src/platform/posix/posix_ipclisten.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -29,28 +29,20 @@
#include "posix_ipc.h"
-int
-nni_ipc_listener_init(nni_ipc_listener **lp)
-{
- nni_ipc_listener *l;
- if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
- return (NNG_ENOMEM);
- }
-
- nni_mtx_init(&l->mtx);
-
- l->pfd = NULL;
- l->closed = false;
- l->started = false;
- l->perms = 0;
-
- nni_aio_list_init(&l->acceptq);
- *lp = l;
- return (0);
-}
+typedef struct {
+ nng_stream_listener sl;
+ nni_posix_pfd * pfd;
+ nng_sockaddr sa;
+ nni_list acceptq;
+ bool started;
+ bool closed;
+ char * path;
+ mode_t perms;
+ nni_mtx mtx;
+} ipc_listener;
static void
-ipc_listener_doclose(nni_ipc_listener *l)
+ipc_listener_doclose(ipc_listener *l)
{
nni_aio *aio;
char * path;
@@ -71,16 +63,17 @@ ipc_listener_doclose(nni_ipc_listener *l)
}
}
-void
-nni_ipc_listener_close(nni_ipc_listener *l)
+static void
+ipc_listener_close(void *arg)
{
+ ipc_listener *l = arg;
nni_mtx_lock(&l->mtx);
ipc_listener_doclose(l);
nni_mtx_unlock(&l->mtx);
}
static void
-ipc_listener_doaccept(nni_ipc_listener *l)
+ipc_listener_doaccept(ipc_listener *l)
{
nni_aio *aio;
@@ -138,7 +131,7 @@ ipc_listener_doaccept(nni_ipc_listener *l)
continue;
}
- if ((rv = nni_posix_ipc_conn_init(&c, pfd)) != 0) {
+ if ((rv = nni_posix_ipc_init(&c, pfd)) != 0) {
nni_posix_pfd_fini(pfd);
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
@@ -146,7 +139,7 @@ ipc_listener_doaccept(nni_ipc_listener *l)
}
nni_aio_list_remove(aio);
- nni_posix_ipc_conn_start(c);
+ nni_posix_ipc_start(c);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
@@ -155,7 +148,7 @@ ipc_listener_doaccept(nni_ipc_listener *l)
static void
ipc_listener_cb(nni_posix_pfd *pfd, int events, void *arg)
{
- nni_ipc_listener *l = arg;
+ ipc_listener *l = arg;
NNI_ARG_UNUSED(pfd);
nni_mtx_lock(&l->mtx);
@@ -173,7 +166,7 @@ ipc_listener_cb(nni_posix_pfd *pfd, int events, void *arg)
static void
ipc_listener_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_listener *l = arg;
+ ipc_listener *l = arg;
// This is dead easy, because we'll ignore the completion if there
// isn't anything to do the accept on!
@@ -222,16 +215,16 @@ ipc_remove_stale(const char *path)
static int
ipc_listener_get_addr(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_listener *l = arg;
+ ipc_listener *l = arg;
return (nni_copyout_sockaddr(&l->sa, buf, szp, t));
}
static int
ipc_listener_set_perms(void *arg, const void *buf, size_t sz, nni_type t)
{
- nni_ipc_listener *l = arg;
- int mode;
- int rv;
+ ipc_listener *l = arg;
+ int mode;
+ int rv;
if ((rv = nni_copyin_int(&mode, buf, sz, 0, S_IFMT, t)) != 0) {
return (rv);
@@ -239,16 +232,14 @@ ipc_listener_set_perms(void *arg, const void *buf, size_t sz, nni_type t)
if ((mode & S_IFMT) != 0) {
return (NNG_EINVAL);
}
- if (l != NULL) {
- mode |= S_IFSOCK; // set IFSOCK to ensure non-zero
- nni_mtx_lock(&l->mtx);
- if (l->started) {
- nni_mtx_unlock(&l->mtx);
- return (NNG_EBUSY);
- }
- l->perms = mode;
+ mode |= S_IFSOCK; // set IFSOCK to ensure non-zero
+ nni_mtx_lock(&l->mtx);
+ if (l->started) {
nni_mtx_unlock(&l->mtx);
+ return (NNG_EBUSY);
}
+ l->perms = mode;
+ nni_mtx_unlock(&l->mtx);
return (0);
}
@@ -266,23 +257,26 @@ static const nni_option ipc_listener_options[] = {
},
};
-int
-nni_ipc_listener_getopt(
- nni_ipc_listener *l, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+ipc_listener_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
+ ipc_listener *l = arg;
return (nni_getopt(ipc_listener_options, name, l, buf, szp, t));
}
-int
-nni_ipc_listener_setopt(nni_ipc_listener *l, const char *name, const void *buf,
- size_t sz, nni_type t)
+static int
+ipc_listener_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
+ ipc_listener *l = arg;
return (nni_setopt(ipc_listener_options, name, l, buf, sz, t));
}
int
-nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
+ipc_listener_listen(void *arg)
{
+ ipc_listener * l = arg;
socklen_t len;
struct sockaddr_storage ss;
int rv;
@@ -290,7 +284,7 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
nni_posix_pfd * pfd;
char * path;
- if (((len = nni_posix_nn2sockaddr(&ss, sa)) == 0) ||
+ if (((len = nni_posix_nn2sockaddr(&ss, &l->sa)) == 0) ||
(ss.ss_family != AF_UNIX)) {
return (NNG_EADDRINVAL);
}
@@ -304,7 +298,7 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
nni_mtx_unlock(&l->mtx);
return (NNG_ECLOSED);
}
- path = nni_strdup(sa->s_ipc.sa_path);
+ path = nni_strdup(l->sa.s_ipc.sa_path);
if (path == NULL) {
return (NNG_ENOMEM);
}
@@ -352,15 +346,15 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
l->pfd = pfd;
l->started = true;
l->path = path;
- l->sa = *sa;
nni_mtx_unlock(&l->mtx);
return (0);
}
-void
-nni_ipc_listener_fini(nni_ipc_listener *l)
+static void
+ipc_listener_free(void *arg)
{
+ ipc_listener * l = arg;
nni_posix_pfd *pfd;
nni_mtx_lock(&l->mtx);
@@ -375,10 +369,11 @@ nni_ipc_listener_fini(nni_ipc_listener *l)
NNI_FREE_STRUCT(l);
}
-void
-nni_ipc_listener_accept(nni_ipc_listener *l, nni_aio *aio)
+static void
+ipc_listener_accept(void *arg, nni_aio *aio)
{
- int rv;
+ ipc_listener *l = arg;
+ int rv;
// Accept is simpler than the connect case. With accept we just
// need to wait for the socket to be readable to indicate an incoming
@@ -410,3 +405,69 @@ nni_ipc_listener_accept(nni_ipc_listener *l, nni_aio *aio)
}
nni_mtx_unlock(&l->mtx);
}
+
+int
+nni_ipc_listener_alloc(nng_stream_listener **lp, const nng_url *url)
+{
+ ipc_listener *l;
+
+ if ((strcmp(url->u_scheme, "ipc") != 0) || (url->u_path == NULL) ||
+ (strlen(url->u_path) == 0) ||
+ (strlen(url->u_path) >= NNG_MAXADDRLEN)) {
+ return (NNG_EADDRINVAL);
+ }
+
+ if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ nni_mtx_init(&l->mtx);
+ nni_aio_list_init(&l->acceptq);
+
+ l->pfd = NULL;
+ l->closed = false;
+ l->started = false;
+ l->perms = 0;
+ l->sa.s_ipc.sa_family = NNG_AF_IPC;
+ strcpy(l->sa.s_ipc.sa_path, url->u_path);
+ l->sl.sl_free = ipc_listener_free;
+ l->sl.sl_close = ipc_listener_close;
+ l->sl.sl_listen = ipc_listener_listen;
+ l->sl.sl_accept = ipc_listener_accept;
+ l->sl.sl_getx = ipc_listener_getx;
+ l->sl.sl_setx = ipc_listener_setx;
+
+ *lp = (void *) l;
+ return (0);
+}
+
+static int
+ipc_check_perms(const void *buf, size_t sz, nni_type t)
+{
+ int32_t mode;
+ int rv;
+
+ if ((rv = nni_copyin_int(&mode, buf, sz, 0, S_IFMT, t)) != 0) {
+ return (rv);
+ }
+ if ((mode & S_IFMT) != 0) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+static const nni_chkoption ipc_chkopts[] = {
+ {
+ .o_name = NNG_OPT_IPC_PERMISSIONS,
+ .o_check = ipc_check_perms,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+int
+nni_ipc_checkopt(const char *name, const void *data, size_t sz, nni_type t)
+{
+ return (nni_chkopt(ipc_chkopts, name, data, sz, t));
+}
diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c
index b4d63b59..bb6db188 100644
--- a/src/platform/posix/posix_resolv_gai.c
+++ b/src/platform/posix/posix_resolv_gai.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>
//
// This software is supplied under the terms of the MIT License, a
@@ -321,10 +321,11 @@ resolv_worker(void *notused)
// Check to make sure we were not canceled.
if ((aio = item->aio) != NULL) {
- nng_sockaddr *sa = nni_aio_get_input(aio, 0);
+
nni_aio_set_prov_extra(aio, 0, NULL);
item->aio = NULL;
- memcpy(sa, &item->sa, sizeof(*sa));
+
+ nni_aio_set_sockaddr(aio, &item->sa);
nni_aio_finish(aio, rv, 0);
NNI_FREE_STRUCT(item);
diff --git a/src/platform/posix/posix_tcp.h b/src/platform/posix/posix_tcp.h
index 788fcbf8..1638df61 100644
--- a/src/platform/posix/posix_tcp.h
+++ b/src/platform/posix/posix_tcp.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 2018 Devolutions <info@devolutions.net>
//
@@ -14,6 +14,7 @@
#include "platform/posix/posix_aio.h"
struct nni_tcp_conn {
+ nng_stream stream;
nni_posix_pfd * pfd;
nni_list readq;
nni_list writeq;
@@ -23,26 +24,5 @@ struct nni_tcp_conn {
nni_tcp_dialer *dialer;
nni_reap_item reap;
};
-
-struct nni_tcp_dialer {
- nni_list connq; // pending connections
- bool closed;
- bool nodelay;
- bool keepalive;
- struct sockaddr_storage src;
- size_t srclen;
- nni_mtx mtx;
-};
-
-struct nni_tcp_listener {
- nni_posix_pfd *pfd;
- nni_list acceptq;
- bool started;
- bool closed;
- bool nodelay;
- bool keepalive;
- nni_mtx mtx;
-};
-
-extern int nni_posix_tcp_conn_init(nni_tcp_conn **, nni_posix_pfd *);
-extern void nni_posix_tcp_conn_start(nni_tcp_conn *, int, int);
+extern int nni_posix_tcp_init(nni_tcp_conn **, nni_posix_pfd *);
+extern void nni_posix_tcp_start(nni_tcp_conn *, int, int);
diff --git a/src/platform/posix/posix_tcpconn.c b/src/platform/posix/posix_tcpconn.c
index ef6ee8e3..0d3c274d 100644
--- a/src/platform/posix/posix_tcpconn.c
+++ b/src/platform/posix/posix_tcpconn.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>
//
@@ -36,7 +36,7 @@
#include "posix_tcp.h"
static void
-tcp_conn_dowrite(nni_tcp_conn *c)
+tcp_dowrite(nni_tcp_conn *c)
{
nni_aio *aio;
int fd;
@@ -118,7 +118,7 @@ tcp_conn_dowrite(nni_tcp_conn *c)
}
static void
-tcp_conn_doread(nni_tcp_conn *c)
+tcp_doread(nni_tcp_conn *c)
{
nni_aio *aio;
int fd;
@@ -195,9 +195,10 @@ tcp_conn_doread(nni_tcp_conn *c)
}
}
-void
-nni_tcp_conn_close(nni_tcp_conn *c)
+static void
+tcp_close(void *arg)
{
+ nni_tcp_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (!c->closed) {
nni_aio *aio;
@@ -212,21 +213,44 @@ nni_tcp_conn_close(nni_tcp_conn *c)
nni_mtx_unlock(&c->mtx);
}
+// tcp_fini may block briefly waiting for the pollq thread.
+// To get that out of our context, we simply reap this.
+static void
+tcp_fini(void *arg)
+{
+ nni_tcp_conn *c = arg;
+ tcp_close(c);
+ nni_posix_pfd_fini(c->pfd);
+ nni_mtx_lock(&c->mtx); // not strictly needed, but shut up TSAN
+ c->pfd = NULL;
+ nni_mtx_unlock(&c->mtx);
+ nni_mtx_fini(&c->mtx);
+
+ NNI_FREE_STRUCT(c);
+}
+
static void
-tcp_conn_cb(nni_posix_pfd *pfd, int events, void *arg)
+tcp_free(void *arg)
+{
+ nni_tcp_conn *c = arg;
+ nni_reap(&c->reap, tcp_fini, arg);
+}
+
+static void
+tcp_cb(nni_posix_pfd *pfd, int events, void *arg)
{
nni_tcp_conn *c = arg;
if (events & (POLLHUP | POLLERR | POLLNVAL)) {
- nni_tcp_conn_close(c);
+ tcp_close(c);
return;
}
nni_mtx_lock(&c->mtx);
if (events & POLLIN) {
- tcp_conn_doread(c);
+ tcp_doread(c);
}
if (events & POLLOUT) {
- tcp_conn_dowrite(c);
+ tcp_dowrite(c);
}
events = 0;
if (!nni_list_empty(&c->writeq)) {
@@ -242,7 +266,7 @@ tcp_conn_cb(nni_posix_pfd *pfd, int events, void *arg)
}
static void
-tcp_conn_cancel(nni_aio *aio, void *arg, int rv)
+tcp_cancel(nni_aio *aio, void *arg, int rv)
{
nni_tcp_conn *c = arg;
@@ -254,18 +278,18 @@ tcp_conn_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_tcp_conn_send(nni_tcp_conn *c, nni_aio *aio)
+static void
+tcp_send(void *arg, nni_aio *aio)
{
-
- int rv;
+ nni_tcp_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
}
nni_mtx_lock(&c->mtx);
- if ((rv = nni_aio_schedule(aio, tcp_conn_cancel, c)) != 0) {
+ if ((rv = nni_aio_schedule(aio, tcp_cancel, c)) != 0) {
nni_mtx_unlock(&c->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -273,7 +297,7 @@ nni_tcp_conn_send(nni_tcp_conn *c, nni_aio *aio)
nni_aio_list_append(&c->writeq, aio);
if (nni_list_first(&c->writeq) == aio) {
- tcp_conn_dowrite(c);
+ tcp_dowrite(c);
// If we are still the first thing on the list, that
// means we didn't finish the job, so arm the poller to
// complete us.
@@ -284,17 +308,18 @@ nni_tcp_conn_send(nni_tcp_conn *c, nni_aio *aio)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_tcp_conn_recv(nni_tcp_conn *c, nni_aio *aio)
+static void
+tcp_recv(void *arg, nni_aio *aio)
{
- int rv;
+ nni_tcp_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
}
nni_mtx_lock(&c->mtx);
- if ((rv = nni_aio_schedule(aio, tcp_conn_cancel, c)) != 0) {
+ if ((rv = nni_aio_schedule(aio, tcp_cancel, c)) != 0) {
nni_mtx_unlock(&c->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -306,7 +331,7 @@ nni_tcp_conn_recv(nni_tcp_conn *c, nni_aio *aio)
// many cases. We also need not arm a list if it was already
// armed.
if (nni_list_first(&c->readq) == aio) {
- tcp_conn_doread(c);
+ tcp_doread(c);
// If we are still the first thing on the list, that
// means we didn't finish the job, so arm the poller to
// complete us.
@@ -317,59 +342,8 @@ nni_tcp_conn_recv(nni_tcp_conn *c, nni_aio *aio)
nni_mtx_unlock(&c->mtx);
}
-int
-nni_tcp_conn_peername(nni_tcp_conn *c, nni_sockaddr *sa)
-{
- struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
- int fd = nni_posix_pfd_fd(c->pfd);
-
- if (getpeername(fd, (void *) &ss, &sslen) != 0) {
- return (nni_plat_errno(errno));
- }
- return (nni_posix_sockaddr2nn(sa, &ss));
-}
-
-int
-nni_tcp_conn_sockname(nni_tcp_conn *c, nni_sockaddr *sa)
-{
- struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
- int fd = nni_posix_pfd_fd(c->pfd);
-
- if (getsockname(fd, (void *) &ss, &sslen) != 0) {
- return (nni_plat_errno(errno));
- }
- return (nni_posix_sockaddr2nn(sa, &ss));
-}
-
-int
-nni_tcp_conn_set_keepalive(nni_tcp_conn *c, bool keep)
-{
- int val = keep ? 1 : 0;
- int fd = nni_posix_pfd_fd(c->pfd);
-
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0) {
- return (nni_plat_errno(errno));
- }
- return (0);
-}
-
-int
-nni_tcp_conn_set_nodelay(nni_tcp_conn *c, bool nodelay)
-{
-
- int val = nodelay ? 1 : 0;
- int fd = nni_posix_pfd_fd(c->pfd);
-
- if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != 0) {
- return (nni_plat_errno(errno));
- }
- return (0);
-}
-
static int
-tcp_conn_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn * c = arg;
struct sockaddr_storage ss;
@@ -388,7 +362,7 @@ tcp_conn_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn * c = arg;
struct sockaddr_storage ss;
@@ -407,7 +381,7 @@ tcp_conn_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
+tcp_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
{
nni_tcp_conn *c = arg;
int fd;
@@ -427,7 +401,7 @@ tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
}
static int
-tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
+tcp_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
{
nni_tcp_conn *c = arg;
int fd;
@@ -447,7 +421,7 @@ tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
}
static int
-tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
int fd = nni_posix_pfd_fd(c->pfd);
@@ -462,7 +436,7 @@ tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
int fd = nni_posix_pfd_fd(c->pfd);
@@ -476,46 +450,46 @@ tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
return (nni_copyout_bool(val, buf, szp, t));
}
-static const nni_option tcp_conn_options[] = {
+static const nni_option tcp_options[] = {
{
.o_name = NNG_OPT_REMADDR,
- .o_get = tcp_conn_get_peername,
+ .o_get = tcp_get_peername,
},
{
.o_name = NNG_OPT_LOCADDR,
- .o_get = tcp_conn_get_sockname,
+ .o_get = tcp_get_sockname,
},
{
.o_name = NNG_OPT_TCP_NODELAY,
- .o_get = tcp_conn_get_nodelay,
- .o_set = tcp_conn_set_nodelay,
+ .o_get = tcp_get_nodelay,
+ .o_set = tcp_set_nodelay,
},
{
.o_name = NNG_OPT_TCP_KEEPALIVE,
- .o_get = tcp_conn_get_keepalive,
- .o_set = tcp_conn_set_keepalive,
+ .o_get = tcp_get_keepalive,
+ .o_set = tcp_set_keepalive,
},
{
.o_name = NULL,
},
};
-int
-nni_tcp_conn_getopt(
- nni_tcp_conn *c, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+tcp_getx(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- return (nni_getopt(tcp_conn_options, name, c, buf, szp, t));
+ nni_tcp_conn *c = arg;
+ return (nni_getopt(tcp_options, name, c, buf, szp, t));
}
-int
-nni_tcp_conn_setopt(
- nni_tcp_conn *c, const char *name, const void *buf, size_t sz, nni_type t)
+static int
+tcp_setx(void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
- return (nni_setopt(tcp_conn_options, name, c, buf, sz, t));
+ nni_tcp_conn *c = arg;
+ return (nni_setopt(tcp_options, name, c, buf, sz, t));
}
int
-nni_posix_tcp_conn_init(nni_tcp_conn **cp, nni_posix_pfd *pfd)
+nni_posix_tcp_init(nni_tcp_conn **cp, nni_posix_pfd *pfd)
{
nni_tcp_conn *c;
@@ -530,12 +504,19 @@ nni_posix_tcp_conn_init(nni_tcp_conn **cp, nni_posix_pfd *pfd)
nni_aio_list_init(&c->readq);
nni_aio_list_init(&c->writeq);
+ c->stream.s_free = tcp_free;
+ c->stream.s_close = tcp_close;
+ c->stream.s_recv = tcp_recv;
+ c->stream.s_send = tcp_send;
+ c->stream.s_getx = tcp_getx;
+ c->stream.s_setx = tcp_setx;
+
*cp = c;
return (0);
}
void
-nni_posix_tcp_conn_start(nni_tcp_conn *c, int nodelay, int keepalive)
+nni_posix_tcp_start(nni_tcp_conn *c, int nodelay, int keepalive)
{
// Configure the initial socket options.
(void) setsockopt(nni_posix_pfd_fd(c->pfd), IPPROTO_TCP, TCP_NODELAY,
@@ -543,18 +524,5 @@ nni_posix_tcp_conn_start(nni_tcp_conn *c, int nodelay, int keepalive)
(void) setsockopt(nni_posix_pfd_fd(c->pfd), SOL_SOCKET, SO_KEEPALIVE,
&keepalive, sizeof(int));
- nni_posix_pfd_set_cb(c->pfd, tcp_conn_cb, c);
-}
-
-void
-nni_tcp_conn_fini(nni_tcp_conn *c)
-{
- nni_tcp_conn_close(c);
- nni_posix_pfd_fini(c->pfd);
- nni_mtx_lock(&c->mtx); // not strictly needed, but shut up TSAN
- c->pfd = NULL;
- nni_mtx_unlock(&c->mtx);
- nni_mtx_fini(&c->mtx);
-
- NNI_FREE_STRUCT(c);
+ nni_posix_pfd_set_cb(c->pfd, tcp_cb, c);
}
diff --git a/src/platform/posix/posix_tcpdial.c b/src/platform/posix/posix_tcpdial.c
index cfb3482c..21ad862d 100644
--- a/src/platform/posix/posix_tcpdial.c
+++ b/src/platform/posix/posix_tcpdial.c
@@ -29,6 +29,16 @@
#include "posix_tcp.h"
+struct nni_tcp_dialer {
+ nni_list connq; // pending connections
+ bool closed;
+ bool nodelay;
+ bool keepalive;
+ struct sockaddr_storage src;
+ size_t srclen;
+ nni_mtx mtx;
+};
+
// Dialer stuff.
int
nni_tcp_dialer_init(nni_tcp_dialer **dp)
@@ -58,9 +68,8 @@ nni_tcp_dialer_close(nni_tcp_dialer *d)
if ((c = nni_aio_get_prov_extra(aio, 0)) != NULL) {
c->dial_aio = NULL;
nni_aio_set_prov_extra(aio, 0, NULL);
- nni_tcp_conn_close(c);
- nni_reap(
- &c->reap, (nni_cb) nni_tcp_conn_fini, c);
+ nng_stream_close(&c->stream);
+ nng_stream_free(&c->stream);
}
nni_aio_finish_error(aio, NNG_ECLOSED);
}
@@ -94,7 +103,7 @@ tcp_dialer_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&d->mtx);
nni_aio_finish_error(aio, rv);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->stream);
}
static void
@@ -142,13 +151,13 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg)
nni_mtx_unlock(&d->mtx);
if (rv != 0) {
- nni_tcp_conn_close(c);
- nni_tcp_conn_fini(c);
+ nng_stream_close(&c->stream);
+ nng_stream_free(&c->stream);
nni_aio_finish_error(aio, rv);
return;
}
- nni_posix_tcp_conn_start(c, nd, ka);
+ nni_posix_tcp_start(c, nd, ka);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
@@ -156,7 +165,7 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg)
// We don't give local address binding support. Outbound dialers always
// get an ephemeral port.
void
-nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
+nni_tcp_dial(nni_tcp_dialer *d, nni_aio *aio)
{
nni_tcp_conn * c;
nni_posix_pfd * pfd = NULL;
@@ -166,12 +175,14 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
int rv;
int ka;
int nd;
+ nng_sockaddr sa;
if (nni_aio_begin(aio) != 0) {
return;
}
- if (((sslen = nni_posix_nn2sockaddr(&ss, sa)) == 0) ||
+ nni_aio_get_sockaddr(aio, &sa);
+ if (((sslen = nni_posix_nn2sockaddr(&ss, &sa)) == 0) ||
((ss.ss_family != AF_INET) && (ss.ss_family != AF_INET6))) {
nni_aio_finish_error(aio, NNG_EADDRINVAL);
return;
@@ -189,7 +200,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_aio_finish_error(aio, rv);
return;
}
- if ((rv = nni_posix_tcp_conn_init(&c, pfd)) != 0) {
+ if ((rv = nni_posix_tcp_init(&c, pfd)) != 0) {
nni_posix_pfd_fini(pfd);
nni_aio_finish_error(aio, rv);
return;
@@ -232,7 +243,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nd = d->nodelay ? 1 : 0;
ka = d->keepalive ? 1 : 0;
nni_mtx_unlock(&d->mtx);
- nni_posix_tcp_conn_start(c, nd, ka);
+ nni_posix_tcp_start(c, nd, ka);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
return;
@@ -240,7 +251,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
error:
nni_aio_set_prov_extra(aio, 0, NULL);
nni_mtx_unlock(&d->mtx);
- nni_reap(&c->reap, (nni_cb) nni_tcp_conn_fini, c);
+ nng_stream_free(&c->stream);
nni_aio_finish_error(aio, rv);
}
diff --git a/src/platform/posix/posix_tcplisten.c b/src/platform/posix/posix_tcplisten.c
index 1e1b84b1..1edeccbc 100644
--- a/src/platform/posix/posix_tcplisten.c
+++ b/src/platform/posix/posix_tcplisten.c
@@ -29,6 +29,16 @@
#include "posix_tcp.h"
+struct nni_tcp_listener {
+ nni_posix_pfd *pfd;
+ nni_list acceptq;
+ bool started;
+ bool closed;
+ bool nodelay;
+ bool keepalive;
+ nni_mtx mtx;
+};
+
int
nni_tcp_listener_init(nni_tcp_listener **lp)
{
@@ -133,7 +143,7 @@ tcp_listener_doaccept(nni_tcp_listener *l)
continue;
}
- if ((rv = nni_posix_tcp_conn_init(&c, pfd)) != 0) {
+ if ((rv = nni_posix_tcp_init(&c, pfd)) != 0) {
nni_posix_pfd_fini(pfd);
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
@@ -143,7 +153,7 @@ tcp_listener_doaccept(nni_tcp_listener *l)
ka = l->keepalive ? 1 : 0;
nd = l->nodelay ? 1 : 0;
nni_aio_list_remove(aio);
- nni_posix_tcp_conn_start(c, nd, ka);
+ nni_posix_tcp_start(c, nd, ka);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
diff --git a/src/platform/windows/win_ipc.h b/src/platform/windows/win_ipc.h
index e8e83957..d410b980 100644
--- a/src/platform/windows/win_ipc.h
+++ b/src/platform/windows/win_ipc.h
@@ -1,7 +1,7 @@
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2018 Devolutions <info@devolutions.net>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -19,45 +19,6 @@
#define IPC_PIPE_PREFIX "\\\\.\\pipe\\"
-struct nni_ipc_conn {
- HANDLE f;
- nni_win_io recv_io;
- nni_win_io send_io;
- nni_win_io conn_io;
- nni_list recv_aios;
- nni_list send_aios;
- nni_aio * conn_aio;
- nng_sockaddr sa;
- bool dialer;
- int recv_rv;
- int send_rv;
- int conn_rv;
- bool closed;
- nni_mtx mtx;
- nni_cv cv;
- nni_reap_item reap;
-};
-
-struct nni_ipc_dialer {
- bool closed; // dialers are locked by the worker lock
- nni_list aios;
- nni_list_node node; // node on worker list
-};
-
-struct nni_ipc_listener {
- char * path;
- bool started;
- bool closed;
- HANDLE f;
- SECURITY_ATTRIBUTES sec_attr;
- nni_list aios;
- nni_mtx mtx;
- nni_cv cv;
- nni_win_io io;
- nni_sockaddr sa;
- int rv;
-};
-
-extern int nni_win_ipc_conn_init(nni_ipc_conn **, HANDLE);
+extern int nni_win_ipc_init(nng_stream **, HANDLE, const nng_sockaddr *, bool);
#endif // NNG_PLATFORM_WIN_WINIPC_H
diff --git a/src/platform/windows/win_ipcconn.c b/src/platform/windows/win_ipcconn.c
index ded9ed76..4d267dd9 100644
--- a/src/platform/windows/win_ipcconn.c
+++ b/src/platform/windows/win_ipcconn.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -15,10 +15,30 @@
#include <stdio.h>
-#define CONN(c) ((nni_ipc_conn *) (c))
+#define CONN(c) ((ipc_conn *) (c))
+
+typedef struct ipc_conn {
+ nng_stream stream;
+ HANDLE f;
+ nni_win_io recv_io;
+ nni_win_io send_io;
+ nni_win_io conn_io;
+ nni_list recv_aios;
+ nni_list send_aios;
+ nni_aio * conn_aio;
+ nng_sockaddr sa;
+ bool dialer;
+ int recv_rv;
+ int send_rv;
+ int conn_rv;
+ bool closed;
+ nni_mtx mtx;
+ nni_cv cv;
+ nni_reap_item reap;
+} ipc_conn;
static void
-ipc_recv_start(nni_ipc_conn *c)
+ipc_recv_start(ipc_conn *c)
{
nni_aio *aio;
unsigned idx;
@@ -75,8 +95,8 @@ again:
static void
ipc_recv_cb(nni_win_io *io, int rv, size_t num)
{
- nni_aio * aio;
- nni_ipc_conn *c = io->ptr;
+ nni_aio * aio;
+ ipc_conn *c = io->ptr;
nni_mtx_lock(&c->mtx);
if ((aio = nni_list_first(&c->recv_aios)) == NULL) {
// Should indicate that it was closed.
@@ -103,7 +123,7 @@ ipc_recv_cb(nni_win_io *io, int rv, size_t num)
static void
ipc_recv_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_conn *c = arg;
+ ipc_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (aio == nni_list_first(&c->recv_aios)) {
c->recv_rv = rv;
@@ -116,10 +136,11 @@ ipc_recv_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_ipc_conn_recv(nni_ipc_conn *c, nni_aio *aio)
+static void
+ipc_recv(void *arg, nni_aio *aio)
{
- int rv;
+ ipc_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
@@ -143,7 +164,7 @@ nni_ipc_conn_recv(nni_ipc_conn *c, nni_aio *aio)
}
static void
-ipc_send_start(nni_ipc_conn *c)
+ipc_send_start(ipc_conn *c)
{
nni_aio *aio;
unsigned idx;
@@ -200,8 +221,8 @@ again:
static void
ipc_send_cb(nni_win_io *io, int rv, size_t num)
{
- nni_aio * aio;
- nni_ipc_conn *c = io->ptr;
+ nni_aio * aio;
+ ipc_conn *c = io->ptr;
nni_mtx_lock(&c->mtx);
if ((aio = nni_list_first(&c->send_aios)) == NULL) {
// Should indicate that it was closed.
@@ -229,7 +250,7 @@ ipc_send_cb(nni_win_io *io, int rv, size_t num)
static void
ipc_send_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_conn *c = arg;
+ ipc_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (aio == nni_list_first(&c->send_aios)) {
c->send_rv = rv;
@@ -242,10 +263,11 @@ ipc_send_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_ipc_conn_send(nni_ipc_conn *c, nni_aio *aio)
+static void
+ipc_send(void *arg, nni_aio *aio)
{
- int rv;
+ ipc_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
@@ -268,35 +290,10 @@ nni_ipc_conn_send(nni_ipc_conn *c, nni_aio *aio)
nni_mtx_unlock(&c->mtx);
}
-int
-nni_win_ipc_conn_init(nni_ipc_conn **connp, HANDLE p)
-{
- nni_ipc_conn *c;
- int rv;
-
- if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
- return (NNG_ENOMEM);
- }
- c->f = INVALID_HANDLE_VALUE;
- nni_mtx_init(&c->mtx);
- nni_cv_init(&c->cv, &c->mtx);
- nni_aio_list_init(&c->recv_aios);
- nni_aio_list_init(&c->send_aios);
-
- if (((rv = nni_win_io_init(&c->recv_io, ipc_recv_cb, c)) != 0) ||
- ((rv = nni_win_io_init(&c->send_io, ipc_send_cb, c)) != 0)) {
- nni_ipc_conn_fini(c);
- return (rv);
- }
-
- c->f = p;
- *connp = c;
- return (0);
-}
-
-void
-nni_ipc_conn_close(nni_ipc_conn *c)
+static void
+ipc_close(void *arg)
{
+ ipc_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (!c->closed) {
c->closed = true;
@@ -316,7 +313,7 @@ nni_ipc_conn_close(nni_ipc_conn *c)
}
static void
-ipc_conn_reap(nni_ipc_conn *c)
+ipc_conn_reap(ipc_conn *c)
{
nni_mtx_lock(&c->mtx);
while ((!nni_list_empty(&c->recv_aios)) ||
@@ -337,10 +334,11 @@ ipc_conn_reap(nni_ipc_conn *c)
NNI_FREE_STRUCT(c);
}
-void
-nni_ipc_conn_fini(nni_ipc_conn *c)
+static void
+ipc_free(void *arg)
{
- nni_ipc_conn_close(c);
+ ipc_conn *c = arg;
+ ipc_close(c);
nni_reap(&c->reap, (nni_cb) ipc_conn_reap, CONN(c));
}
@@ -386,16 +384,51 @@ static const nni_option ipc_conn_options[] = {
},
};
-int
-nni_ipc_conn_setopt(nni_ipc_conn *c, const char *name, const void *val,
- size_t sz, nni_opt_type t)
+static int
+ipc_setx(void *arg, const char *nm, const void *val, size_t sz, nni_opt_type t)
+{
+ ipc_conn *c = arg;
+ return (nni_setopt(ipc_conn_options, nm, c, val, sz, t));
+}
+
+static int
+ipc_getx(void *arg, const char *nm, void *val, size_t *szp, nni_opt_type t)
{
- return (nni_setopt(ipc_conn_options, name, c, val, sz, t));
+ ipc_conn *c = arg;
+ return (nni_getopt(ipc_conn_options, nm, c, val, szp, t));
}
int
-nni_ipc_conn_getopt(
- nni_ipc_conn *c, const char *name, void *val, size_t *szp, nni_opt_type t)
+nni_win_ipc_init(
+ nng_stream **connp, HANDLE p, const nng_sockaddr *sa, bool dialer)
{
- return (nni_getopt(ipc_conn_options, name, c, val, szp, t));
+ ipc_conn *c;
+ int rv;
+
+ if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ c->f = INVALID_HANDLE_VALUE;
+ nni_mtx_init(&c->mtx);
+ nni_cv_init(&c->cv, &c->mtx);
+ nni_aio_list_init(&c->recv_aios);
+ nni_aio_list_init(&c->send_aios);
+ c->dialer = dialer;
+ c->sa = *sa;
+ c->stream.s_free = ipc_free;
+ c->stream.s_close = ipc_close;
+ c->stream.s_send = ipc_send;
+ c->stream.s_recv = ipc_recv;
+ c->stream.s_getx = ipc_getx;
+ c->stream.s_setx = ipc_setx;
+
+ if (((rv = nni_win_io_init(&c->recv_io, ipc_recv_cb, c)) != 0) ||
+ ((rv = nni_win_io_init(&c->send_io, ipc_send_cb, c)) != 0)) {
+ ipc_free(c);
+ return (rv);
+ }
+
+ c->f = p;
+ *connp = (void *) c;
+ return (0);
}
diff --git a/src/platform/windows/win_ipcdial.c b/src/platform/windows/win_ipcdial.c
index 98d848ae..be2a82b3 100644
--- a/src/platform/windows/win_ipcdial.c
+++ b/src/platform/windows/win_ipcdial.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -15,19 +15,14 @@
#include <stdio.h>
-int
-nni_ipc_dialer_init(nni_ipc_dialer **dp)
-{
- nni_ipc_dialer *d;
-
- if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
- return (NNG_ENOMEM);
- }
- d->closed = false;
- nni_aio_list_init(&d->aios);
- *dp = d;
- return (0);
-}
+typedef struct ipc_dialer {
+ nng_stream_dialer sd;
+ bool closed; // dialers are locked by the worker lock
+ nni_list aios;
+ nni_list_node node; // node on worker list
+ char * path;
+ nni_sockaddr sa;
+} ipc_dialer;
// Windows IPC is a bit different on the client side. There is no
// support for asynchronous connection, but we can fake it with a
@@ -52,7 +47,7 @@ ipc_dial_thr(void *arg)
nni_mtx_lock(&w->mtx);
for (;;) {
- nni_ipc_dialer *d;
+ ipc_dialer *d;
if (w->exit) {
break;
@@ -63,21 +58,19 @@ ipc_dial_thr(void *arg)
}
while ((d = nni_list_first(&w->workers)) != NULL) {
- nni_ipc_conn *c;
- nni_aio * aio;
- HANDLE f;
- int rv;
- char * path;
+ nng_stream *c;
+ nni_aio * aio;
+ HANDLE f;
+ int rv;
if ((aio = nni_list_first(&d->aios)) == NULL) {
nni_list_remove(&w->workers, d);
continue;
}
- path = nni_aio_get_prov_extra(aio, 0);
-
- f = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, 0,
- NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ f = CreateFileA(d->path, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
+ NULL);
if (f == INVALID_HANDLE_VALUE) {
switch ((rv = GetLastError())) {
@@ -99,29 +92,20 @@ ipc_dial_thr(void *arg)
break;
}
nni_list_remove(&d->aios, aio);
- nni_aio_set_prov_extra(aio, 0, NULL);
- nni_strfree(path);
nni_aio_finish_error(aio, rv);
continue;
}
nni_list_remove(&d->aios, aio);
- nni_aio_set_prov_extra(aio, 0, NULL);
if (((rv = nni_win_io_register(f)) != 0) ||
- ((rv = nni_win_ipc_conn_init(&c, f)) != 0)) {
+ ((rv = nni_win_ipc_init(&c, f, &d->sa, true)) !=
+ 0)) {
DisconnectNamedPipe(f);
CloseHandle(f);
nni_aio_finish_error(aio, rv);
- nni_strfree(path);
continue;
}
- c->dialer = true;
- c->sa.s_ipc.sa_family = NNG_AF_IPC;
- snprintf(c->sa.s_ipc.sa_path,
- sizeof(c->sa.s_ipc.sa_path), "%s",
- path + strlen(IPC_PIPE_PREFIX));
- nni_strfree(path);
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
@@ -140,27 +124,23 @@ ipc_dial_thr(void *arg)
static void
ipc_dial_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_dialer *d = arg;
- ipc_dial_work * w = &ipc_connecter;
+ ipc_dialer * d = arg;
+ ipc_dial_work *w = &ipc_connecter;
nni_mtx_lock(&w->mtx);
if (nni_aio_list_active(aio)) {
- char *path;
if (nni_list_active(&w->waiters, d)) {
nni_list_remove(&w->waiters, d);
nni_cv_wake(&w->cv);
}
nni_aio_list_remove(aio);
- path = nni_aio_get_prov_extra(aio, 0);
- nni_aio_set_prov_extra(aio, 0, NULL);
- nni_strfree(path);
nni_aio_finish_error(aio, rv);
}
nni_mtx_unlock(&w->mtx);
}
-void
-nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
+static void
+ipc_dialer_dial(ipc_dialer *d, nni_aio *aio)
{
ipc_dial_work *w = &ipc_connecter;
char * path;
@@ -169,12 +149,8 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
if (nni_aio_begin(aio) != 0) {
return;
}
- if (sa->s_family != NNG_AF_IPC) {
- nni_aio_finish_error(aio, NNG_EADDRINVAL);
- return;
- }
if ((rv = nni_asprintf(
- &path, IPC_PIPE_PREFIX "%s", sa->s_ipc.sa_path)) != 0) {
+ &path, IPC_PIPE_PREFIX "%s", d->sa.s_ipc.sa_path)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
@@ -182,19 +158,16 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_mtx_lock(&w->mtx);
if ((rv = nni_aio_schedule(aio, ipc_dial_cancel, d)) != 0) {
nni_mtx_unlock(&w->mtx);
- nni_strfree(path);
nni_aio_finish_error(aio, rv);
return;
}
if (d->closed) {
nni_mtx_unlock(&w->mtx);
- nni_strfree(path);
nni_aio_finish_error(aio, NNG_ECLOSED);
return;
}
- nni_aio_set_prov_extra(aio, 0, path);
nni_list_append(&d->aios, aio);
if (nni_list_first(&d->aios) == aio) {
nni_list_append(&w->waiters, d);
@@ -203,16 +176,10 @@ nni_ipc_dialer_dial(nni_ipc_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_mtx_unlock(&w->mtx);
}
-void
-nni_ipc_dialer_fini(nni_ipc_dialer *d)
-{
- nni_ipc_dialer_close(d);
- NNI_FREE_STRUCT(d);
-}
-
-void
-nni_ipc_dialer_close(nni_ipc_dialer *d)
+static void
+ipc_dialer_close(void *arg)
{
+ ipc_dialer * d = arg;
ipc_dial_work *w = &ipc_connecter;
nni_aio * aio;
@@ -228,6 +195,17 @@ nni_ipc_dialer_close(nni_ipc_dialer *d)
nni_mtx_unlock(&w->mtx);
}
+static void
+ipc_dialer_free(void *arg)
+{
+ ipc_dialer *d = arg;
+ ipc_dialer_close(d);
+ if (d->path) {
+ nni_strfree(d->path);
+ }
+ NNI_FREE_STRUCT(d);
+}
+
static const nni_option ipc_dialer_options[] = {
{
.o_name = NULL,
@@ -235,17 +213,50 @@ static const nni_option ipc_dialer_options[] = {
};
int
-nni_ipc_dialer_setopt(nni_ipc_dialer *d, const char *name, const void *buf,
- size_t sz, nni_type t)
+ipc_dialer_setx(
+ void *arg, const char *nm, const void *buf, size_t sz, nni_type t)
+{
+ ipc_dialer *d = arg;
+ return (nni_setopt(ipc_dialer_options, nm, d, buf, sz, t));
+}
+
+int
+ipc_dialer_getx(void *arg, const char *nm, void *buf, size_t *szp, nni_type t)
{
- return (nni_setopt(ipc_dialer_options, name, d, buf, sz, t));
+ ipc_dialer *d = arg;
+ return (nni_getopt(ipc_dialer_options, nm, d, buf, szp, t));
}
int
-nni_ipc_dialer_getopt(
- nni_ipc_dialer *d, const char *name, void *buf, size_t *szp, nni_type t)
+nni_ipc_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
{
- return (nni_getopt(ipc_dialer_options, name, d, buf, szp, t));
+ ipc_dialer *d;
+ int rv;
+
+ if ((strcmp(url->u_scheme, "ipc") != 0) || (url->u_path == NULL) ||
+ (strlen(url->u_path) == 0)) {
+ return (NNG_EADDRINVAL);
+ }
+ if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ if ((rv = nni_asprintf(&d->path, IPC_PIPE_PREFIX "%s", url->u_path)) !=
+ 0) {
+ NNI_FREE_STRUCT(d);
+ return (rv);
+ }
+ snprintf(d->sa.s_ipc.sa_path, NNG_MAXADDRLEN, "%s", url->u_path);
+ d->sa.s_ipc.sa_family = NNG_AF_IPC;
+ d->closed = false;
+ d->sd.sd_free = ipc_dialer_free;
+ d->sd.sd_close = ipc_dialer_close;
+ d->sd.sd_dial = ipc_dialer_dial;
+ d->sd.sd_getx = ipc_dialer_getx;
+ d->sd.sd_setx = ipc_dialer_setx;
+ nni_aio_list_init(&d->aios);
+ *dp = (void *) d;
+ return (0);
}
int
@@ -254,8 +265,8 @@ nni_win_ipc_sysinit(void)
int rv;
ipc_dial_work *worker = &ipc_connecter;
- NNI_LIST_INIT(&worker->workers, nni_ipc_dialer, node);
- NNI_LIST_INIT(&worker->waiters, nni_ipc_dialer, node);
+ NNI_LIST_INIT(&worker->workers, ipc_dialer, node);
+ NNI_LIST_INIT(&worker->waiters, ipc_dialer, node);
nni_mtx_init(&worker->mtx);
nni_cv_init(&worker->cv, &worker->mtx);
diff --git a/src/platform/windows/win_ipclisten.c b/src/platform/windows/win_ipclisten.c
index 4b3660ec..a3922d06 100644
--- a/src/platform/windows/win_ipclisten.c
+++ b/src/platform/windows/win_ipclisten.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -15,12 +15,27 @@
#include <stdio.h>
+typedef struct {
+ nng_stream_listener sl;
+ char * path;
+ bool started;
+ bool closed;
+ HANDLE f;
+ SECURITY_ATTRIBUTES sec_attr;
+ nni_list aios;
+ nni_mtx mtx;
+ nni_cv cv;
+ nni_win_io io;
+ nni_sockaddr sa;
+ int rv;
+} ipc_listener;
+
static void
-ipc_accept_done(nni_ipc_listener *l, int rv)
+ipc_accept_done(ipc_listener *l, int rv)
{
- nni_aio * aio;
- HANDLE f;
- nni_ipc_conn *c;
+ nni_aio * aio;
+ HANDLE f;
+ nng_stream *c;
aio = nni_list_first(&l->aios);
nni_list_remove(&l->aios, aio);
@@ -50,24 +65,21 @@ ipc_accept_done(nni_ipc_listener *l, int rv)
}
if (((rv = nni_win_io_register(f)) != 0) ||
- ((rv = nni_win_ipc_conn_init(&c, l->f)) != 0)) {
+ ((rv = nni_win_ipc_init(&c, l->f, &l->sa, false)) != 0)) {
DisconnectNamedPipe(l->f);
DisconnectNamedPipe(f);
CloseHandle(f);
nni_aio_finish_error(aio, rv);
return;
}
- l->f = f;
- c->sa.s_ipc.sa_family = NNG_AF_IPC;
- snprintf(c->sa.s_ipc.sa_path, sizeof(c->sa.s_ipc.sa_path), "%s",
- l->path + strlen(IPC_PIPE_PREFIX));
- c->dialer = false;
+ // Install the replacement pipe.
+ l->f = f;
nni_aio_set_output(aio, 0, c);
nni_aio_finish(aio, 0, 0);
}
static void
-ipc_accept_start(nni_ipc_listener *l)
+ipc_accept_start(ipc_listener *l)
{
nni_aio *aio;
@@ -102,7 +114,7 @@ ipc_accept_start(nni_ipc_listener *l)
static void
ipc_accept_cb(nni_win_io *io, int rv, size_t cnt)
{
- nni_ipc_listener *l = io->ptr;
+ ipc_listener *l = io->ptr;
NNI_ARG_UNUSED(cnt);
@@ -122,37 +134,12 @@ ipc_accept_cb(nni_win_io *io, int rv, size_t cnt)
nni_mtx_unlock(&l->mtx);
}
-int
-nni_ipc_listener_init(nni_ipc_listener **lp)
-{
- nni_ipc_listener *l;
- int rv;
-
- if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
- return (NNG_ENOMEM);
- }
- if ((rv = nni_win_io_init(&l->io, ipc_accept_cb, l)) != 0) {
- NNI_FREE_STRUCT(l);
- return (rv);
- }
- l->started = false;
- l->closed = false;
- l->sec_attr.nLength = sizeof(l->sec_attr);
- l->sec_attr.lpSecurityDescriptor = NULL;
- l->sec_attr.bInheritHandle = FALSE;
- nni_aio_list_init(&l->aios);
- nni_mtx_init(&l->mtx);
- nni_cv_init(&l->cv, &l->mtx);
- *lp = l;
- return (0);
-}
-
static int
ipc_listener_set_sec_desc(void *arg, const void *buf, size_t sz, nni_type t)
{
- nni_ipc_listener *l = arg;
- void * desc;
- int rv;
+ ipc_listener *l = arg;
+ void * desc;
+ int rv;
if ((rv = nni_copyin_ptr(&desc, buf, sz, t)) != 0) {
return (rv);
@@ -160,22 +147,20 @@ ipc_listener_set_sec_desc(void *arg, const void *buf, size_t sz, nni_type t)
if (!IsValidSecurityDescriptor((SECURITY_DESCRIPTOR *) desc)) {
return (NNG_EINVAL);
}
- if (l != NULL) {
- nni_mtx_lock(&l->mtx);
- if (l->started) {
- nni_mtx_unlock(&l->mtx);
- return (NNG_EBUSY);
- }
- l->sec_attr.lpSecurityDescriptor = desc;
+ nni_mtx_lock(&l->mtx);
+ if (l->started) {
nni_mtx_unlock(&l->mtx);
+ return (NNG_EBUSY);
}
+ l->sec_attr.lpSecurityDescriptor = desc;
+ nni_mtx_unlock(&l->mtx);
return (0);
}
static int
ipc_listener_get_addr(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_ipc_listener *l = arg;
+ ipc_listener *l = arg;
return ((nni_copyout_sockaddr(&l->sa, buf, szp, t)));
}
@@ -194,25 +179,28 @@ static const nni_option ipc_listener_options[] = {
};
int
-nni_ipc_listener_setopt(nni_ipc_listener *l, const char *name, const void *buf,
- size_t sz, nni_type t)
+ipc_listener_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
+ ipc_listener *l = arg;
return (nni_setopt(ipc_listener_options, name, l, buf, sz, t));
}
int
-nni_ipc_listener_getopt(
- nni_ipc_listener *l, const char *name, void *buf, size_t *szp, nni_type t)
+ipc_listener_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
+ ipc_listener *l = arg;
return (nni_getopt(ipc_listener_options, name, l, buf, szp, t));
}
-int
-nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
+static int
+ipc_listener_listen(void *arg)
{
- int rv;
- HANDLE f;
- char * path;
+ ipc_listener *l = arg;
+ int rv;
+ HANDLE f;
+ char * path;
nni_mtx_lock(&l->mtx);
if (l->started) {
@@ -223,7 +211,7 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
nni_mtx_unlock(&l->mtx);
return (NNG_ECLOSED);
}
- rv = nni_asprintf(&path, IPC_PIPE_PREFIX "%s", sa->s_ipc.sa_path);
+ rv = nni_asprintf(&path, IPC_PIPE_PREFIX "%s", l->sa.s_ipc.sa_path);
if (rv != 0) {
nni_mtx_unlock(&l->mtx);
return (rv);
@@ -255,7 +243,6 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
l->f = f;
l->path = path;
l->started = true;
- l->sa = *sa;
nni_mtx_unlock(&l->mtx);
return (0);
}
@@ -263,7 +250,7 @@ nni_ipc_listener_listen(nni_ipc_listener *l, const nni_sockaddr *sa)
static void
ipc_accept_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_ipc_listener *l = arg;
+ ipc_listener *l = arg;
nni_mtx_unlock(&l->mtx);
if (aio == nni_list_first(&l->aios)) {
@@ -277,9 +264,10 @@ ipc_accept_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ipc_listener_accept(nni_ipc_listener *l, nni_aio *aio)
+static void
+ipc_listener_accept(void *arg, nni_aio *aio)
{
+ ipc_listener *l = arg;
if (nni_aio_begin(aio) != 0) {
return;
}
@@ -301,9 +289,10 @@ nni_ipc_listener_accept(nni_ipc_listener *l, nni_aio *aio)
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ipc_listener_close(nni_ipc_listener *l)
+static void
+ipc_listener_close(void *arg)
{
+ ipc_listener *l = arg;
nni_mtx_lock(&l->mtx);
if (!l->closed) {
l->closed = true;
@@ -316,9 +305,10 @@ nni_ipc_listener_close(nni_ipc_listener *l)
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ipc_listener_fini(nni_ipc_listener *l)
+static void
+ipc_listener_free(void *arg)
{
+ ipc_listener *l = arg;
nni_mtx_lock(&l->mtx);
while (!nni_list_empty(&l->aios)) {
nni_cv_wait(&l->cv);
@@ -330,3 +320,72 @@ nni_ipc_listener_fini(nni_ipc_listener *l)
nni_mtx_fini(&l->mtx);
NNI_FREE_STRUCT(l);
}
+
+int
+nni_ipc_listener_alloc(nng_stream_listener **lp, const nng_url *url)
+{
+ ipc_listener *l;
+ int rv;
+
+ if ((strcmp(url->u_scheme, "ipc") != 0) || (url->u_path == NULL) ||
+ (strlen(url->u_path) == 0)) {
+ return (NNG_EADDRINVAL);
+ }
+ if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ if ((rv = nni_win_io_init(&l->io, ipc_accept_cb, l)) != 0) {
+ NNI_FREE_STRUCT(l);
+ return (rv);
+ }
+ l->started = false;
+ l->closed = false;
+ l->sec_attr.nLength = sizeof(l->sec_attr);
+ l->sec_attr.lpSecurityDescriptor = NULL;
+ l->sec_attr.bInheritHandle = FALSE;
+ l->sa.s_ipc.sa_family = NNG_AF_IPC;
+ l->sl.sl_free = ipc_listener_free;
+ l->sl.sl_close = ipc_listener_close;
+ l->sl.sl_listen = ipc_listener_listen;
+ l->sl.sl_accept = ipc_listener_accept;
+ l->sl.sl_getx = ipc_listener_getx;
+ l->sl.sl_setx = ipc_listener_setx;
+ snprintf(l->sa.s_ipc.sa_path, NNG_MAXADDRLEN, "%s", url->u_path);
+ nni_aio_list_init(&l->aios);
+ nni_mtx_init(&l->mtx);
+ nni_cv_init(&l->cv, &l->mtx);
+ *lp = (void *) l;
+ return (0);
+}
+
+static int
+ipc_check_sec_desc(const void *buf, size_t sz, nni_type t)
+{
+ void *desc;
+ int rv;
+
+ if ((rv = nni_copyin_ptr(&desc, buf, sz, t)) != 0) {
+ return (rv);
+ }
+ if (!IsValidSecurityDescriptor((SECURITY_DESCRIPTOR *) desc)) {
+ return (NNG_EINVAL);
+ }
+
+ return (0);
+}
+
+static const nni_chkoption ipc_chkopts[] = {
+ {
+ .o_name = NNG_OPT_IPC_SECURITY_DESCRIPTOR,
+ .o_check = ipc_check_sec_desc,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+int
+nni_ipc_checkopt(const char *name, const void *data, size_t sz, nni_type t)
+{
+ return (nni_chkopt(ipc_chkopts, name, data, sz, t));
+}
diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c
index d361a1e8..e01dba3b 100644
--- a/src/platform/windows/win_resolv.c
+++ b/src/platform/windows/win_resolv.c
@@ -134,25 +134,27 @@ resolv_task(resolv_item *item)
}
}
- if (probe != NULL) {
+ if ((probe != NULL) && (item->aio != NULL)) {
struct sockaddr_in * sin;
struct sockaddr_in6 *sin6;
- nni_sockaddr * sa = &item->sa;
+ nni_sockaddr sa;
switch (probe->ai_addr->sa_family) {
case AF_INET:
- rv = 0;
- sin = (void *) probe->ai_addr;
- sa->s_in.sa_family = NNG_AF_INET;
- sa->s_in.sa_port = item->port;
- sa->s_in.sa_addr = sin->sin_addr.s_addr;
+ rv = 0;
+ sin = (void *) probe->ai_addr;
+ sa.s_in.sa_family = NNG_AF_INET;
+ sa.s_in.sa_port = item->port;
+ sa.s_in.sa_addr = sin->sin_addr.s_addr;
+ nni_aio_set_sockaddr(item->aio, &sa);
break;
case AF_INET6:
- rv = 0;
- sin6 = (void *) probe->ai_addr;
- sa->s_in6.sa_family = NNG_AF_INET6;
- sa->s_in6.sa_port = item->port;
- memcpy(sa->s_in6.sa_addr, sin6->sin6_addr.s6_addr, 16);
+ rv = 0;
+ sin6 = (void *) probe->ai_addr;
+ sa.s_in6.sa_family = NNG_AF_INET6;
+ sa.s_in6.sa_port = item->port;
+ memcpy(sa.s_in6.sa_addr, sin6->sin6_addr.s6_addr, 16);
+ nni_aio_set_sockaddr(item->aio, &sa);
break;
}
}
@@ -294,10 +296,9 @@ resolv_worker(void *notused)
// Check to make sure we were not canceled.
if ((aio = item->aio) != NULL) {
- nng_sockaddr *sa = nni_aio_get_input(aio, 0);
nni_aio_set_prov_extra(aio, 0, NULL);
item->aio = NULL;
- memcpy(sa, &item->sa, sizeof(*sa));
+
nni_aio_finish(aio, rv, 0);
NNI_FREE_STRUCT(item);
diff --git a/src/platform/windows/win_tcp.h b/src/platform/windows/win_tcp.h
index 1b34aa29..b37b2353 100644
--- a/src/platform/windows/win_tcp.h
+++ b/src/platform/windows/win_tcp.h
@@ -1,7 +1,7 @@
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2018 Devolutions <info@devolutions.net>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -17,6 +17,7 @@
#include "core/nng_impl.h"
struct nni_tcp_conn {
+ nng_stream ops;
SOCKET s;
nni_win_io recv_io;
nni_win_io send_io;
@@ -37,18 +38,6 @@ struct nni_tcp_conn {
nni_cv cv;
};
-struct nni_tcp_dialer {
- LPFN_CONNECTEX connectex; // looked up name via ioctl
- nni_list aios; // in flight connections
- bool closed;
- bool nodelay; // initial value for child conns
- bool keepalive; // initial value for child conns
- SOCKADDR_STORAGE src;
- size_t srclen;
- nni_mtx mtx;
- nni_reap_item reap;
-};
-
struct nni_tcp_listener {
SOCKET s;
nni_list aios;
diff --git a/src/platform/windows/win_tcpconn.c b/src/platform/windows/win_tcpconn.c
index 54d22dea..c77bbc72 100644
--- a/src/platform/windows/win_tcpconn.c
+++ b/src/platform/windows/win_tcpconn.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>
//
@@ -110,8 +110,8 @@ tcp_recv_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&c->mtx);
}
-void
-nni_tcp_conn_recv(nni_tcp_conn *c, nni_aio *aio)
+static void
+tcp_recv(nni_tcp_conn *c, nni_aio *aio)
{
int rv;
@@ -225,10 +225,11 @@ tcp_send_cb(nni_win_io *io, int rv, size_t num)
nni_aio_finish_synch(aio, rv, num);
}
-void
-nni_tcp_conn_send(nni_tcp_conn *c, nni_aio *aio)
+static void
+tcp_send(void *arg, nni_aio *aio)
{
- int rv;
+ nni_tcp_conn *c = arg;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
@@ -251,49 +252,10 @@ nni_tcp_conn_send(nni_tcp_conn *c, nni_aio *aio)
nni_mtx_unlock(&c->mtx);
}
-int
-nni_win_tcp_conn_init(nni_tcp_conn **connp, SOCKET s)
-{
- nni_tcp_conn *c;
- int rv;
- BOOL yes;
- DWORD no;
-
- // Don't inherit the handle (CLOEXEC really).
- SetHandleInformation((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
-
- if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
- return (NNG_ENOMEM);
- }
- c->s = INVALID_SOCKET;
- nni_mtx_init(&c->mtx);
- nni_cv_init(&c->cv, &c->mtx);
- nni_aio_list_init(&c->recv_aios);
- nni_aio_list_init(&c->send_aios);
- c->conn_aio = NULL;
-
- if (((rv = nni_win_io_init(&c->recv_io, tcp_recv_cb, c)) != 0) ||
- ((rv = nni_win_io_init(&c->send_io, tcp_send_cb, c)) != 0) ||
- ((rv = nni_win_io_register((HANDLE) s)) != 0)) {
- nni_tcp_conn_fini(c);
- return (rv);
- }
-
- no = 0;
- (void) setsockopt(
- s, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &no, sizeof(no));
- yes = 1;
- (void) setsockopt(
- s, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(yes));
-
- c->s = s;
- *connp = c;
- return (0);
-}
-
-void
-nni_tcp_conn_close(nni_tcp_conn *c)
+static void
+tcp_close(void *arg)
{
+ nni_tcp_conn *c = arg;
nni_mtx_lock(&c->mtx);
if (!c->closed) {
c->closed = true;
@@ -310,50 +272,8 @@ nni_tcp_conn_close(nni_tcp_conn *c)
nni_mtx_unlock(&c->mtx);
}
-int
-nni_tcp_conn_peername(nni_tcp_conn *c, nni_sockaddr *sa)
-{
- if (nni_win_sockaddr2nn(sa, &c->peername) < 0) {
- return (NNG_EADDRINVAL);
- }
- return (0);
-}
-
-int
-nni_tcp_conn_sockname(nni_tcp_conn *c, nni_sockaddr *sa)
-{
- if (nni_win_sockaddr2nn(sa, &c->sockname) < 0) {
- return (NNG_EADDRINVAL);
- }
- return (0);
-}
-
-int
-nni_tcp_conn_set_nodelay(nni_tcp_conn *c, bool val)
-{
- BOOL b;
- b = val ? TRUE : FALSE;
- if (setsockopt(
- c->s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)) != 0) {
- return (nni_win_error(WSAGetLastError()));
- }
- return (0);
-}
-
-int
-nni_tcp_conn_set_keepalive(nni_tcp_conn *c, bool val)
-{
- BOOL b;
- b = val ? TRUE : FALSE;
- if (setsockopt(
- c->s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)) != 0) {
- return (nni_win_error(WSAGetLastError()));
- }
- return (0);
-}
-
static int
-tcp_conn_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
nng_sockaddr sa;
@@ -365,7 +285,7 @@ tcp_conn_get_peername(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
nng_sockaddr sa;
@@ -377,7 +297,7 @@ tcp_conn_get_sockname(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
+tcp_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
{
nni_tcp_conn *c = arg;
bool val;
@@ -395,7 +315,7 @@ tcp_conn_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t)
}
static int
-tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
+tcp_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
{
nni_tcp_conn *c = arg;
bool val;
@@ -414,7 +334,7 @@ tcp_conn_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t)
}
static int
-tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
BOOL b = 0;
@@ -428,7 +348,7 @@ tcp_conn_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t)
}
static int
-tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
+tcp_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
{
nni_tcp_conn *c = arg;
BOOL b = 0;
@@ -441,48 +361,49 @@ tcp_conn_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t)
return (nni_copyout_bool(b, buf, szp, t));
}
-static const nni_option tcp_conn_options[] = {
+static const nni_option tcp_options[] = {
{
.o_name = NNG_OPT_REMADDR,
- .o_get = tcp_conn_get_peername,
+ .o_get = tcp_get_peername,
},
{
.o_name = NNG_OPT_LOCADDR,
- .o_get = tcp_conn_get_sockname,
+ .o_get = tcp_get_sockname,
},
{
.o_name = NNG_OPT_TCP_NODELAY,
- .o_get = tcp_conn_get_nodelay,
- .o_set = tcp_conn_set_nodelay,
+ .o_get = tcp_get_nodelay,
+ .o_set = tcp_set_nodelay,
},
{
.o_name = NNG_OPT_TCP_KEEPALIVE,
- .o_get = tcp_conn_get_keepalive,
- .o_set = tcp_conn_set_keepalive,
+ .o_get = tcp_get_keepalive,
+ .o_set = tcp_set_keepalive,
},
{
.o_name = NULL,
},
};
-int
-nni_tcp_conn_getopt(
- nni_tcp_conn *c, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+tcp_getx(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- return (nni_getopt(tcp_conn_options, name, c, buf, szp, t));
+ nni_tcp_conn *c = arg;
+ return (nni_getopt(tcp_options, name, c, buf, szp, t));
}
-int
-nni_tcp_conn_setopt(
- nni_tcp_conn *c, const char *name, const void *buf, size_t sz, nni_type t)
+static int
+tcp_setx(void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
- return (nni_setopt(tcp_conn_options, name, c, buf, sz, t));
+ nni_tcp_conn *c = arg;
+ return (nni_setopt(tcp_options, name, c, buf, sz, t));
}
-void
-nni_tcp_conn_fini(nni_tcp_conn *c)
+static void
+tcp_free(void *arg)
{
- nni_tcp_conn_close(c);
+ nni_tcp_conn *c = arg;
+ tcp_close(c);
nni_mtx_lock(&c->mtx);
while ((!nni_list_empty(&c->recv_aios)) ||
@@ -502,3 +423,49 @@ nni_tcp_conn_fini(nni_tcp_conn *c)
nni_mtx_fini(&c->mtx);
NNI_FREE_STRUCT(c);
}
+
+int
+nni_win_tcp_conn_init(nni_tcp_conn **connp, SOCKET s)
+{
+ nni_tcp_conn *c;
+ int rv;
+ BOOL yes;
+ DWORD no;
+
+ // Don't inherit the handle (CLOEXEC really).
+ SetHandleInformation((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
+
+ if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ c->s = INVALID_SOCKET;
+ nni_mtx_init(&c->mtx);
+ nni_cv_init(&c->cv, &c->mtx);
+ nni_aio_list_init(&c->recv_aios);
+ nni_aio_list_init(&c->send_aios);
+ c->conn_aio = NULL;
+ c->ops.s_close = tcp_close;
+ c->ops.s_free = tcp_free;
+ c->ops.s_send = tcp_send;
+ c->ops.s_recv = tcp_recv;
+ c->ops.s_getx = tcp_getx;
+ c->ops.s_setx = tcp_setx;
+
+ if (((rv = nni_win_io_init(&c->recv_io, tcp_recv_cb, c)) != 0) ||
+ ((rv = nni_win_io_init(&c->send_io, tcp_send_cb, c)) != 0) ||
+ ((rv = nni_win_io_register((HANDLE) s)) != 0)) {
+ tcp_free(c);
+ return (rv);
+ }
+
+ no = 0;
+ (void) setsockopt(
+ s, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &no, sizeof(no));
+ yes = 1;
+ (void) setsockopt(
+ s, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(yes));
+
+ c->s = s;
+ *connp = c;
+ return (0);
+}
diff --git a/src/platform/windows/win_tcpdial.c b/src/platform/windows/win_tcpdial.c
index 64b4e800..6bb3d92a 100644
--- a/src/platform/windows/win_tcpdial.c
+++ b/src/platform/windows/win_tcpdial.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>
//
@@ -16,6 +16,18 @@
#include <malloc.h>
#include <stdio.h>
+struct nni_tcp_dialer {
+ LPFN_CONNECTEX connectex; // looked up name via ioctl
+ nni_list aios; // in flight connections
+ bool closed;
+ bool nodelay; // initial value for child conns
+ bool keepalive; // initial value for child conns
+ SOCKADDR_STORAGE src; // source address
+ size_t srclen;
+ nni_mtx mtx;
+ nni_reap_item reap;
+};
+
int
nni_tcp_dialer_init(nni_tcp_dialer **dp)
{
@@ -137,7 +149,7 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt)
nni_mtx_unlock(&d->mtx);
if (rv != 0) {
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
} else {
DWORD yes = 1;
@@ -156,19 +168,22 @@ tcp_dial_cb(nni_win_io *io, int rv, size_t cnt)
}
void
-nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
+nni_tcp_dial(nni_tcp_dialer *d, nni_aio *aio)
{
SOCKET s;
SOCKADDR_STORAGE ss;
int len;
nni_tcp_conn * c;
int rv;
+ nng_sockaddr sa;
+
+ nni_aio_get_sockaddr(aio, &sa);
if (nni_aio_begin(aio) != 0) {
return;
}
- if ((len = nni_win_nn2sockaddr(&ss, sa)) <= 0) {
+ if ((len = nni_win_nn2sockaddr(&ss, &sa)) <= 0) {
nni_aio_finish_error(aio, NNG_EADDRINVAL);
return;
}
@@ -179,7 +194,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
}
if ((rv = nni_win_tcp_conn_init(&c, s)) != 0) {
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
@@ -194,7 +209,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_mtx_lock(&d->mtx);
if (d->closed) {
nni_mtx_unlock(&d->mtx);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, NNG_ECLOSED);
return;
}
@@ -212,7 +227,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
if (bind(s, (SOCKADDR *) &c->sockname, len) != 0) {
rv = nni_win_error(GetLastError());
nni_mtx_unlock(&d->mtx);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
@@ -221,7 +236,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
nni_aio_set_prov_extra(aio, 0, c);
if ((rv = nni_aio_schedule(aio, tcp_dial_cancel, d)) != 0) {
nni_mtx_unlock(&d->mtx);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
@@ -234,8 +249,7 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
if ((rv = GetLastError()) != ERROR_IO_PENDING) {
nni_aio_list_remove(aio);
nni_mtx_unlock(&d->mtx);
-
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c
index 9cf16985..e98a0c37 100644
--- a/src/platform/windows/win_tcplisten.c
+++ b/src/platform/windows/win_tcplisten.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>
//
@@ -98,7 +98,7 @@ tcp_accept_cb(nni_win_io *io, int rv, size_t cnt)
nni_mtx_unlock(&l->mtx);
if (rv != 0) {
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
@@ -309,7 +309,7 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio)
((rv = nni_aio_schedule(aio, tcp_accept_cancel, l)) != 0)) {
nni_aio_set_prov_extra(aio, 0, NULL);
nni_mtx_unlock(&l->mtx);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
@@ -320,7 +320,7 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio)
// Fast failure (synchronous.)
nni_aio_list_remove(aio);
nni_mtx_unlock(&l->mtx);
- nni_tcp_conn_fini(c);
+ nng_stream_free(&c->ops);
nni_aio_finish_error(aio, rv);
return;
}
diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h
index 569e8532..45738318 100644
--- a/src/supplemental/http/http_api.h
+++ b/src/supplemental/http/http_api.h
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -96,9 +96,7 @@ extern void *nni_http_conn_get_ctx(nni_http_conn *);
// These initialization functions create stream for HTTP transactions.
// They should only be used by the server or client HTTP implementations,
// and are not for use by other code.
-extern int nni_http_conn_init_tcp(nni_http_conn **, nni_tcp_conn *);
-extern int nni_http_conn_init_tls(
- nni_http_conn **, struct nng_tls_config *, nni_tcp_conn *);
+extern int nni_http_conn_init(nni_http_conn **, nng_stream *);
extern void nni_http_conn_close(nni_http_conn *);
extern void nni_http_conn_fini(nni_http_conn *);
@@ -207,6 +205,11 @@ extern int nni_http_server_set_tls(nni_http_server *, struct nng_tls_config *);
extern int nni_http_server_get_tls(
nni_http_server *, struct nng_tls_config **);
+extern int nni_http_server_setx(
+ nni_http_server *, const char *, const void *, size_t, nni_type);
+extern int nni_http_server_getx(
+ nni_http_server *, const char *, void *, size_t *, nni_type);
+
// nni_http_server_start starts listening on the supplied port.
extern int nni_http_server_start(nni_http_server *);
@@ -350,6 +353,11 @@ extern int nni_http_client_set_tls(nni_http_client *, struct nng_tls_config *);
extern int nni_http_client_get_tls(
nni_http_client *, struct nng_tls_config **);
+extern int nni_http_client_setx(
+ nni_http_client *, const char *, const void *, size_t, nni_type);
+extern int nni_http_client_getx(
+ nni_http_client *, const char *, void *, size_t *, nni_type);
+
extern void nni_http_client_connect(nni_http_client *, nni_aio *);
// nni_http_transact_conn is used to perform a round-trip exchange (i.e. a
diff --git a/src/supplemental/http/http_client.c b/src/supplemental/http/http_client.c
index 798cbe14..c35dcaa8 100644
--- a/src/supplemental/http/http_client.c
+++ b/src/supplemental/http/http_client.c
@@ -1,6 +1,7 @@
//
-// 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>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -14,25 +15,20 @@
#include <string.h>
#include "core/nng_impl.h"
-#include "nng/supplemental/tls/tls.h"
#include "supplemental/tls/tls_api.h"
+#include <nng/supplemental/tls/tls.h>
+
#include "http_api.h"
static nni_mtx http_txn_lk;
struct nng_http_client {
- nni_list aios;
- nni_mtx mtx;
- bool closed;
- bool resolving;
- nng_tls_config *tls;
- nni_aio * aio;
- nng_sockaddr sa;
- nni_tcp_dialer *dialer;
- char * host;
- char * port;
- nni_url * url;
+ nni_list aios;
+ nni_mtx mtx;
+ bool closed;
+ nni_aio * aio;
+ nng_stream_dialer *dialer;
};
static void
@@ -43,9 +39,7 @@ http_dial_start(nni_http_client *c)
if ((aio = nni_list_first(&c->aios)) == NULL) {
return;
}
- c->resolving = true;
- nni_aio_set_input(c->aio, 0, &c->sa);
- nni_tcp_resolv(c->host, c->port, NNG_AF_UNSPEC, 0, c->aio);
+ nng_stream_dialer_dial(c->dialer, c->aio);
}
static void
@@ -54,7 +48,7 @@ http_dial_cb(void *arg)
nni_http_client *c = arg;
nni_aio * aio;
int rv;
- nni_tcp_conn * tcp;
+ nng_stream * stream;
nni_http_conn * conn;
nni_mtx_lock(&c->mtx);
@@ -63,9 +57,9 @@ http_dial_cb(void *arg)
if ((aio = nni_list_first(&c->aios)) == NULL) {
// User abandoned request, and no residuals left.
nni_mtx_unlock(&c->mtx);
- if ((rv == 0) && !c->resolving) {
- tcp = nni_aio_get_output(c->aio, 0);
- nni_tcp_conn_fini(tcp);
+ if (rv == 0) {
+ stream = nni_aio_get_output(c->aio, 0);
+ nng_stream_free(stream);
}
return;
}
@@ -78,28 +72,16 @@ http_dial_cb(void *arg)
return;
}
- if (c->resolving) {
- // This was a DNS lookup -- advance to normal TCP connect.
- c->resolving = false;
- nni_tcp_dialer_dial(c->dialer, &c->sa, c->aio);
- nni_mtx_unlock(&c->mtx);
- return;
- }
-
nni_aio_list_remove(aio);
- tcp = nni_aio_get_output(c->aio, 0);
- NNI_ASSERT(tcp != NULL);
+ stream = nni_aio_get_output(c->aio, 0);
+ NNI_ASSERT(stream != NULL);
- if (c->tls != NULL) {
- rv = nni_http_conn_init_tls(&conn, c->tls, tcp);
- } else {
- rv = nni_http_conn_init_tcp(&conn, tcp);
- }
+ rv = nni_http_conn_init(&conn, stream);
http_dial_start(c);
nni_mtx_unlock(&c->mtx);
if (rv != 0) {
- // the conn_init function will have already discard tcp.
+ // the conn_init function will have already discard stream.
nni_aio_finish_error(aio, rv);
return;
}
@@ -112,16 +94,8 @@ void
nni_http_client_fini(nni_http_client *c)
{
nni_aio_fini(c->aio);
- nni_tcp_dialer_fini(c->dialer);
+ nng_stream_dialer_free(c->dialer);
nni_mtx_fini(&c->mtx);
-#ifdef NNG_SUPP_TLS
- if (c->tls != NULL) {
- nni_tls_config_fini(c->tls);
- }
-#endif
- nni_strfree(c->host);
- nni_strfree(c->port);
-
NNI_FREE_STRUCT(c);
}
@@ -130,59 +104,37 @@ nni_http_client_init(nni_http_client **cp, const nni_url *url)
{
int rv;
nni_http_client *c;
+ nng_url myurl;
+
+ // Rewrite URLs to either TLS or TCP.
+ memcpy(&myurl, url, sizeof(myurl));
+ if ((strcmp(url->u_scheme, "http") == 0) ||
+ (strcmp(url->u_scheme, "ws") == 0)) {
+ myurl.u_scheme = "tcp";
+ } else if ((strcmp(url->u_scheme, "https") == 0) ||
+ (strcmp(url->u_scheme, "wss") == 0)) {
+ myurl.u_scheme = "tls+tcp";
+ } else {
+ return (NNG_EADDRINVAL);
+ }
if (strlen(url->u_hostname) == 0) {
// We require a valid hostname.
return (NNG_EADDRINVAL);
}
- if ((strcmp(url->u_scheme, "http") != 0) &&
-#ifdef NNG_SUPP_TLS
- (strcmp(url->u_scheme, "https") != 0) &&
- (strcmp(url->u_scheme, "wss") != 0) &&
-#endif
- (strcmp(url->u_scheme, "ws") != 0)) {
- return (NNG_EADDRINVAL);
- }
if ((c = NNI_ALLOC_STRUCT(c)) == NULL) {
return (NNG_ENOMEM);
}
nni_mtx_init(&c->mtx);
nni_aio_list_init(&c->aios);
- if (((c->host = nni_strdup(url->u_hostname)) == NULL) ||
- ((strlen(url->u_port) != 0) &&
- ((c->port = nni_strdup(url->u_port)) == NULL))) {
- nni_http_client_fini(c);
- return (NNG_ENOMEM);
- }
-
-#ifdef NNG_SUPP_TLS
- if ((strcmp(url->u_scheme, "https") == 0) ||
- (strcmp(url->u_scheme, "wss") == 0)) {
- rv = nni_tls_config_init(&c->tls, NNG_TLS_MODE_CLIENT);
- if (rv != 0) {
- nni_http_client_fini(c);
- return (rv);
- }
- // Take the server name right from the client URL. We only
- // consider the name, as the port is never part of the
- // certificate.
- rv = nng_tls_config_server_name(c->tls, url->u_hostname);
- if (rv != 0) {
- nni_http_client_fini(c);
- return (rv);
- }
- // Note that the application has to supply the location of
- // certificates. We could probably use a default based
- // on environment or common locations used by OpenSSL, but
- // as there is no way to *unload* the cert file, lets not
- // do that. (We might want to consider a mode to reset.)
+ if ((rv = nng_stream_dialer_alloc_url(&c->dialer, &myurl)) != 0) {
+ nni_http_client_fini(c);
+ return (rv);
}
-#endif
- if (((rv = nni_tcp_dialer_init(&c->dialer)) != 0) ||
- ((rv = nni_aio_init(&c->aio, http_dial_cb, c)) != 0)) {
+ if ((rv = nni_aio_init(&c->aio, http_dial_cb, c)) != 0) {
nni_http_client_fini(c);
return (rv);
}
@@ -192,46 +144,37 @@ nni_http_client_init(nni_http_client **cp, const nni_url *url)
}
int
-nni_http_client_set_tls(nni_http_client *c, struct nng_tls_config *tls)
+nni_http_client_set_tls(nni_http_client *c, nng_tls_config *tls)
{
-#ifdef NNG_SUPP_TLS
- struct nng_tls_config *old;
- nni_mtx_lock(&c->mtx);
- old = c->tls;
- c->tls = tls;
- if (tls != NULL) {
- nni_tls_config_hold(tls);
- }
- nni_mtx_unlock(&c->mtx);
- if (old != NULL) {
- nni_tls_config_fini(old);
- }
- return (0);
-#else
- NNI_ARG_UNUSED(c);
- NNI_ARG_UNUSED(tls);
- return (NNG_EINVAL);
-#endif
+ int rv;
+ rv = nni_stream_dialer_setx(c->dialer, NNG_OPT_TLS_CONFIG, &tls,
+ sizeof(tls), NNI_TYPE_POINTER);
+ return (rv);
}
int
-nni_http_client_get_tls(nni_http_client *c, struct nng_tls_config **tlsp)
+nni_http_client_get_tls(nni_http_client *c, nng_tls_config **tlsp)
{
-#ifdef NNG_SUPP_TLS
- nni_mtx_lock(&c->mtx);
- if (c->tls == NULL) {
- nni_mtx_unlock(&c->mtx);
- return (NNG_EINVAL);
- }
- nni_tls_config_hold(c->tls);
- *tlsp = c->tls;
- nni_mtx_unlock(&c->mtx);
- return (0);
-#else
- NNI_ARG_UNUSED(c);
- NNI_ARG_UNUSED(tlsp);
- return (NNG_ENOTSUP);
-#endif
+ size_t sz = sizeof(*tlsp);
+ int rv;
+ rv = nni_stream_dialer_getx(
+ c->dialer, NNG_OPT_TLS_CONFIG, tlsp, &sz, NNI_TYPE_POINTER);
+ return (rv);
+}
+
+int
+nni_http_client_setx(nni_http_client *c, const char *name, const void *buf,
+ size_t sz, nni_type t)
+{
+ // We have no local options, but we just pass them straight through.
+ return (nni_stream_dialer_setx(c->dialer, name, buf, sz, t));
+}
+
+int
+nni_http_client_getx(
+ nni_http_client *c, const char *name, void *buf, size_t *szp, nni_type t)
+{
+ return (nni_stream_dialer_getx(c->dialer, name, buf, szp, t));
}
static void
diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c
index 7c6159cd..1fc2c34e 100644
--- a/src/supplemental/http/http_conn.c
+++ b/src/supplemental/http/http_conn.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -40,25 +40,6 @@ enum write_flavor {
HTTP_WR_RES,
};
-typedef void (*http_read_fn)(void *, nni_aio *);
-typedef void (*http_write_fn)(void *, nni_aio *);
-typedef void (*http_close_fn)(void *);
-typedef void (*http_fini_fn)(void *);
-typedef int (*http_addr_fn)(void *, nni_sockaddr *);
-typedef int (*http_getopt_fn)(
- void *, const char *, void *, size_t *, nni_type);
-typedef int (*http_setopt_fn)(
- void *, const char *, const void *, size_t, nni_type);
-
-typedef struct {
- http_read_fn h_read;
- http_write_fn h_write;
- http_getopt_fn h_getopt;
- http_setopt_fn h_setopt;
- http_close_fn h_close;
- http_fini_fn h_fini;
-} http_tran;
-
#define SET_RD_FLAVOR(aio, f) \
nni_aio_set_prov_extra(aio, 0, ((void *) (intptr_t)(f)))
#define GET_RD_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0))
@@ -67,17 +48,11 @@ typedef struct {
#define GET_WR_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0))
struct nng_http_conn {
- void * sock;
- http_read_fn rd;
- http_write_fn wr;
- http_setopt_fn setopt;
- http_getopt_fn getopt;
- http_close_fn close;
- http_fini_fn fini;
- void * ctx;
- bool closed;
- nni_list rdq; // high level http read requests
- nni_list wrq; // high level http write requests
+ nng_stream *sock;
+ void * ctx;
+ bool closed;
+ nni_list rdq; // high level http read requests
+ nni_list wrq; // high level http write requests
nni_aio *rd_uaio; // user aio for read
nni_aio *wr_uaio; // user aio for write
@@ -138,7 +113,7 @@ http_close(nni_http_conn *conn)
}
if (conn->sock != NULL) {
- conn->close(conn->sock);
+ nng_stream_close(conn->sock);
}
}
@@ -204,7 +179,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
// to get *any* data for a partial RAW read.)
nni_aio_set_data(conn->rd_aio, 1, NULL);
nni_aio_set_iov(conn->rd_aio, niov, iov);
- conn->rd(conn->sock, conn->rd_aio);
+ nng_stream_recv(conn->sock, conn->rd_aio);
return (NNG_EAGAIN);
case HTTP_RD_REQ:
@@ -220,7 +195,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
iov1.iov_len = conn->rd_bufsz - conn->rd_put;
nni_aio_set_iov(conn->rd_aio, 1, &iov1);
nni_aio_set_data(conn->rd_aio, 1, aio);
- conn->rd(conn->sock, conn->rd_aio);
+ nng_stream_recv(conn->sock, conn->rd_aio);
}
return (rv);
@@ -237,7 +212,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
iov1.iov_len = conn->rd_bufsz - conn->rd_put;
nni_aio_set_iov(conn->rd_aio, 1, &iov1);
nni_aio_set_data(conn->rd_aio, 1, aio);
- conn->rd(conn->sock, conn->rd_aio);
+ nng_stream_recv(conn->sock, conn->rd_aio);
}
return (rv);
@@ -254,7 +229,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
iov1.iov_len = conn->rd_bufsz - conn->rd_put;
nni_aio_set_iov(conn->rd_aio, 1, &iov1);
nni_aio_set_data(conn->rd_aio, 1, aio);
- conn->rd(conn->sock, conn->rd_aio);
+ nng_stream_recv(conn->sock, conn->rd_aio);
}
return (rv);
}
@@ -428,7 +403,7 @@ http_wr_start(nni_http_conn *conn)
nni_aio_get_iov(aio, &niov, &iov);
nni_aio_set_iov(conn->wr_aio, niov, iov);
- conn->wr(conn->sock, conn->wr_aio);
+ nng_stream_send(conn->sock, conn->wr_aio);
}
static void
@@ -475,7 +450,7 @@ http_wr_cb(void *arg)
if (nni_aio_iov_count(aio) > 0) {
// We have more to transmit - start another and leave
// (we will get called again when it is done).
- conn->wr(conn->sock, aio);
+ nng_stream_send(conn->sock, aio);
nni_mtx_unlock(&conn->mtx);
return;
}
@@ -680,7 +655,7 @@ nni_http_conn_getopt(
if (conn->closed) {
rv = NNG_ECLOSED;
} else {
- rv = conn->getopt(conn->sock, name, buf, szp, t);
+ rv = nni_stream_getx(conn->sock, name, buf, szp, t);
}
nni_mtx_unlock(&conn->mtx);
return (rv);
@@ -695,7 +670,7 @@ nni_http_conn_setopt(nni_http_conn *conn, const char *name, const void *buf,
if (conn->closed) {
rv = NNG_ECLOSED;
} else {
- rv = conn->setopt(conn->sock, name, buf, sz, t);
+ rv = nni_stream_setx(conn->sock, name, buf, sz, t);
}
nni_mtx_unlock(&conn->mtx);
return (rv);
@@ -709,8 +684,8 @@ nni_http_conn_fini(nni_http_conn *conn)
nni_mtx_lock(&conn->mtx);
http_close(conn);
- if ((conn->sock != NULL) && (conn->fini != NULL)) {
- conn->fini(conn->sock);
+ if (conn->sock != NULL) {
+ nng_stream_free(conn->sock);
conn->sock = NULL;
}
nni_mtx_unlock(&conn->mtx);
@@ -723,7 +698,7 @@ nni_http_conn_fini(nni_http_conn *conn)
}
static int
-http_init(nni_http_conn **connp, http_tran *tran, void *data)
+http_init(nni_http_conn **connp, nng_stream *data)
{
nni_http_conn *conn;
int rv;
@@ -747,73 +722,19 @@ http_init(nni_http_conn **connp, http_tran *tran, void *data)
return (rv);
}
- conn->sock = data;
- conn->rd = tran->h_read;
- conn->wr = tran->h_write;
- conn->close = tran->h_close;
- conn->fini = tran->h_fini;
- conn->getopt = tran->h_getopt;
- conn->setopt = tran->h_setopt;
+ conn->sock = data;
*connp = conn;
return (0);
}
-static http_tran http_tcp_ops = {
- .h_read = (http_read_fn) nni_tcp_conn_recv,
- .h_write = (http_write_fn) nni_tcp_conn_send,
- .h_close = (http_close_fn) nni_tcp_conn_close,
- .h_fini = (http_fini_fn) nni_tcp_conn_fini,
- .h_getopt = (http_getopt_fn) nni_tcp_conn_getopt,
- .h_setopt = (http_setopt_fn) nni_tcp_conn_setopt,
-};
-
int
-nni_http_conn_init_tcp(nni_http_conn **connp, nni_tcp_conn *tcp)
+nni_http_conn_init(nni_http_conn **connp, nng_stream *stream)
{
int rv;
- if ((rv = http_init(connp, &http_tcp_ops, tcp)) != 0) {
- nni_tcp_conn_fini(tcp);
- }
- return (rv);
-}
-
-#ifdef NNG_SUPP_TLS
-static http_tran http_tls_ops = {
- .h_read = (http_read_fn) nni_tls_recv,
- .h_write = (http_write_fn) nni_tls_send,
- .h_close = (http_close_fn) nni_tls_close,
- .h_fini = (http_fini_fn) nni_tls_fini,
- .h_getopt = (http_getopt_fn) nni_tls_getopt,
- .h_setopt = (http_setopt_fn) nni_tls_setopt,
-};
-
-int
-nni_http_conn_init_tls(
- nni_http_conn **connp, struct nng_tls_config *cfg, nni_tcp_conn *tcp)
-{
- nni_tls *tls;
- int rv;
-
- if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) {
- nni_tcp_conn_fini(tcp);
- return (rv);
- }
-
- if ((rv = http_init(connp, &http_tls_ops, tls)) != 0) {
- nni_tls_fini(tls);
+ if ((rv = http_init(connp, stream)) != 0) {
+ nng_stream_free(stream);
}
return (rv);
}
-#else
-int
-nni_http_conn_init_tls(
- nni_http_conn **connp, struct nng_tls_config *cfg, nni_tcp_conn *tcp)
-{
- NNI_ARG_UNUSED(connp);
- NNI_ARG_UNUSED(cfg);
- nni_tcp_conn_fini(tcp);
- return (NNG_ENOTSUP);
-}
-#endif // NNG_SUPP_TLS
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c
index a6343d87..939273b7 100644
--- a/src/supplemental/http/http_server.c
+++ b/src/supplemental/http/http_server.c
@@ -1,7 +1,8 @@
//
-// 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 QXSoftware <lh563566994@126.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -68,22 +69,21 @@ typedef struct http_error {
} http_error;
struct nng_http_server {
- nng_sockaddr addr;
- nni_list_node node;
- int refcnt;
- int starts;
- nni_list handlers;
- nni_list conns;
- nni_mtx mtx;
- bool closed;
- nng_tls_config * tls;
- nni_aio * accaio;
- nni_tcp_listener *listener;
- char * port;
- char * hostname;
- nni_list errors;
- nni_mtx errors_mtx;
- nni_reap_item reap;
+ nng_sockaddr addr;
+ nni_list_node node;
+ int refcnt;
+ int starts;
+ nni_list handlers;
+ nni_list conns;
+ nni_mtx mtx;
+ bool closed;
+ nni_aio * accaio;
+ nng_stream_listener *listener;
+ char * port;
+ char * hostname;
+ nni_list errors;
+ nni_mtx errors_mtx;
+ nni_reap_item reap;
};
int
@@ -720,13 +720,13 @@ http_sconn_cbdone(void *arg)
}
static int
-http_sconn_init(http_sconn **scp, nni_http_server *s, nni_tcp_conn *tcp)
+http_sconn_init(http_sconn **scp, nng_stream *stream)
{
http_sconn *sc;
int rv;
if ((sc = NNI_ALLOC_STRUCT(sc)) == NULL) {
- nni_tcp_conn_fini(tcp);
+ nng_stream_free(stream);
return (NNG_ENOMEM);
}
@@ -741,11 +741,7 @@ http_sconn_init(http_sconn **scp, nni_http_server *s, nni_tcp_conn *tcp)
return (rv);
}
- if (s->tls != NULL) {
- rv = nni_http_conn_init_tls(&sc->conn, s->tls, tcp);
- } else {
- rv = nni_http_conn_init_tcp(&sc->conn, tcp);
- }
+ rv = nni_http_conn_init(&sc->conn, stream);
if (rv != 0) {
http_sconn_close(sc);
return (rv);
@@ -760,7 +756,7 @@ http_server_acccb(void *arg)
{
nni_http_server *s = arg;
nni_aio * aio = s->accaio;
- nni_tcp_conn * tcp;
+ nng_stream * stream;
http_sconn * sc;
int rv;
@@ -768,22 +764,22 @@ http_server_acccb(void *arg)
if ((rv = nni_aio_result(aio)) != 0) {
if (!s->closed) {
// try again?
- nni_tcp_listener_accept(s->listener, s->accaio);
+ nng_stream_listener_accept(s->listener, s->accaio);
}
nni_mtx_unlock(&s->mtx);
return;
}
- tcp = nni_aio_get_output(aio, 0);
+ stream = nni_aio_get_output(aio, 0);
if (s->closed) {
// If we're closing, then reject this one.
- nni_tcp_conn_fini(tcp);
+ nng_stream_free(stream);
nni_mtx_unlock(&s->mtx);
return;
}
- if (http_sconn_init(&sc, s, tcp) != 0) {
- // The TCP structure is already cleaned up.
+ if (http_sconn_init(&sc, stream) != 0) {
+ // The stream structure is already cleaned up.
// Start another accept attempt.
- nni_tcp_listener_accept(s->listener, s->accaio);
+ nng_stream_listener_accept(s->listener, s->accaio);
nni_mtx_unlock(&s->mtx);
return;
}
@@ -792,7 +788,7 @@ http_server_acccb(void *arg)
sc->handler = NULL;
nni_http_read_req(sc->conn, sc->req, sc->rxaio);
- nni_tcp_listener_accept(s->listener, s->accaio);
+ nng_stream_listener_accept(s->listener, s->accaio);
nni_mtx_unlock(&s->mtx);
}
@@ -812,20 +808,13 @@ http_server_fini(nni_http_server *s)
nni_mtx_unlock(&s->mtx);
return;
}
- if (s->listener != NULL) {
- nni_tcp_listener_fini(s->listener);
- }
+ nng_stream_listener_free(s->listener);
while ((h = nni_list_first(&s->handlers)) != NULL) {
nni_list_remove(&s->handlers, h);
h->refcnt--;
nni_http_handler_fini(h);
}
nni_mtx_unlock(&s->mtx);
-#ifdef NNG_SUPP_TLS
- if (s->tls != NULL) {
- nni_tls_config_fini(s->tls);
- }
-#endif
nni_mtx_lock(&s->errors_mtx);
while ((epage = nni_list_first(&s->errors)) != NULL) {
nni_list_remove(&s->errors, epage);
@@ -847,16 +836,20 @@ http_server_init(nni_http_server **serverp, const nni_url *url)
{
nni_http_server *s;
int rv;
- nni_aio * aio;
-
- if ((strcmp(url->u_scheme, "http") != 0) &&
-#ifdef NNG_SUPP_TLS
- (strcmp(url->u_scheme, "https") != 0) &&
- (strcmp(url->u_scheme, "wss") != 0) &&
-#endif
- (strcmp(url->u_scheme, "ws") != 0)) {
+ nng_url myurl;
+
+ // Rewrite URLs to either TLS or TCP.
+ memcpy(&myurl, url, sizeof(myurl));
+ if ((strcmp(url->u_scheme, "http") == 0) ||
+ (strcmp(url->u_scheme, "ws") == 0)) {
+ myurl.u_scheme = "tcp";
+ } else if ((strcmp(url->u_scheme, "https") == 0) ||
+ (strcmp(url->u_scheme, "wss") == 0)) {
+ myurl.u_scheme = "tls+tcp";
+ } else {
return (NNG_EADDRINVAL);
}
+
if ((s = NNI_ALLOC_STRUCT(s)) == NULL) {
return (NNG_ENOMEM);
}
@@ -884,34 +877,11 @@ http_server_init(nni_http_server **serverp, const nni_url *url)
return (NNG_ENOMEM);
}
-#ifdef NNG_SUPP_TLS
- if ((strcmp(url->u_scheme, "https") == 0) ||
- (strcmp(url->u_scheme, "wss") == 0)) {
- rv = nni_tls_config_init(&s->tls, NNG_TLS_MODE_SERVER);
- if (rv != 0) {
- http_server_fini(s);
- return (rv);
- }
- }
-#endif
-
- // Do the DNS lookup *now*. This means that this is
- // synchronous, but it should be fast, since it should either
- // resolve as a number, or resolve locally, without having to
- // hit up DNS.
- if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
- http_server_fini(s);
- return (rv);
- }
- nni_aio_set_input(aio, 0, &s->addr);
- nni_tcp_resolv(s->hostname, s->port, NNG_AF_UNSPEC, true, aio);
- nni_aio_wait(aio);
- rv = nni_aio_result(aio);
- nni_aio_fini(aio);
- if (rv != 0) {
+ if ((rv = nng_stream_listener_alloc_url(&s->listener, &myurl)) != 0) {
http_server_fini(s);
return (rv);
}
+
s->refcnt = 1;
*serverp = s;
return (0);
@@ -950,15 +920,10 @@ static int
http_server_start(nni_http_server *s)
{
int rv;
- if ((rv = nni_tcp_listener_init(&s->listener)) != 0) {
- return (rv);
- }
- if ((rv = nni_tcp_listener_listen(s->listener, &s->addr)) != 0) {
- nni_tcp_listener_fini(s->listener);
- s->listener = NULL;
+ if ((rv = nng_stream_listener_listen(s->listener)) != 0) {
return (rv);
}
- nni_tcp_listener_accept(s->listener, s->accaio);
+ nng_stream_listener_accept(s->listener, s->accaio);
return (0);
}
@@ -992,7 +957,7 @@ http_server_stop(nni_http_server *s)
// Close the TCP endpoint that is listening.
if (s->listener) {
- nni_tcp_listener_close(s->listener);
+ nng_stream_listener_close(s->listener);
}
// Stopping the server is a hard stop -- it aborts any work
@@ -1764,50 +1729,37 @@ nni_http_handler_init_static(nni_http_handler **hpp, const char *uri,
}
int
-nni_http_server_set_tls(nni_http_server *s, nng_tls_config *tcfg)
+nni_http_server_set_tls(nni_http_server *s, nng_tls_config *tls)
{
-#ifdef NNG_SUPP_TLS
- nng_tls_config *old;
- nni_mtx_lock(&s->mtx);
- if (s->starts) {
- nni_mtx_unlock(&s->mtx);
- return (NNG_EBUSY);
- }
- old = s->tls;
- s->tls = tcfg;
- if (tcfg) {
- nni_tls_config_hold(tcfg);
- }
- nni_mtx_unlock(&s->mtx);
- if (old) {
- nni_tls_config_fini(old);
- }
- return (0);
-#else
- NNI_ARG_UNUSED(s);
- NNI_ARG_UNUSED(tcfg);
- return (NNG_ENOTSUP);
-#endif
+ int rv;
+ rv = nni_stream_listener_setx(s->listener, NNG_OPT_TLS_CONFIG, &tls,
+ sizeof(tls), NNI_TYPE_POINTER);
+ return (rv);
}
int
-nni_http_server_get_tls(nni_http_server *s, nng_tls_config **tp)
+nni_http_server_get_tls(nni_http_server *s, nng_tls_config **tlsp)
{
-#ifdef NNG_SUPP_TLS
- nni_mtx_lock(&s->mtx);
- if (s->tls == NULL) {
- nni_mtx_unlock(&s->mtx);
- return (NNG_EINVAL);
- }
- nni_tls_config_hold(s->tls);
- *tp = s->tls;
- nni_mtx_unlock(&s->mtx);
- return (0);
-#else
- NNI_ARG_UNUSED(s);
- NNI_ARG_UNUSED(tp);
- return (NNG_ENOTSUP);
-#endif
+ size_t sz = sizeof(*tlsp);
+ int rv;
+ rv = nni_stream_listener_getx(
+ s->listener, NNG_OPT_TLS_CONFIG, tlsp, &sz, NNI_TYPE_POINTER);
+ return (rv);
+}
+
+int
+nni_http_server_setx(nni_http_server *s, const char *name, const void *buf,
+ size_t sz, nni_type t)
+{
+ // We have no local options, but we just pass them straight through.
+ return (nni_stream_listener_setx(s->listener, name, buf, sz, t));
+}
+
+int
+nni_http_server_getx(
+ nni_http_server *s, const char *name, void *buf, size_t *szp, nni_type t)
+{
+ return (nni_stream_listener_getx(s->listener, name, buf, szp, t));
}
void
diff --git a/src/supplemental/ipc/CMakeLists.txt b/src/supplemental/ipc/CMakeLists.txt
deleted file mode 100644
index 3bc0e4de..00000000
--- a/src/supplemental/ipc/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright 2018 Capitar IT Group BV <info@capitar.com>
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-# Copyright 2018 Devolutions <info@devolutions.net>
-#
-# 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.
-#
-
-set(_SRCS supplemental/ipc/ipc.c
- ${PROJECT_SOURCE_DIR}/include/nng/supplemental/ipc/ipc.h
-)
-
-set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
diff --git a/src/supplemental/ipc/ipc.c b/src/supplemental/ipc/ipc.c
deleted file mode 100644
index cf78dfbd..00000000
--- a/src/supplemental/ipc/ipc.c
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2018 Devolutions <info@devolutions.net>
-//
-// 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 <stddef.h>
-#include <stdint.h>
-
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-#include "core/nng_impl.h"
-
-// This is our "public" IPC API. This allows applications to access
-// basic IPC functions, using our AIO framework. Most applications will
-// not need this.
-
-// We treat nng_ipc as nni_ipc_conn, nng_ipc_dialer as nni_ipc_dialer,
-// and nng_ipc_listener as nni_ipc_listener. We cast through void to
-// provide isolation of the names in a way that makes the compiler happy.
-// It turns out we can pretty much just wrap the platform API for IPC that
-// we have already created.
-
-void
-nng_ipc_close(nng_ipc *ipc)
-{
- nni_ipc_conn_close((void *) ipc);
-}
-
-void
-nng_ipc_free(nng_ipc *ipc)
-{
- nni_ipc_conn_fini((void *) ipc);
-}
-
-void
-nng_ipc_send(nng_ipc *ipc, nng_aio *aio)
-{
- nni_ipc_conn_send((void *) ipc, aio);
-}
-
-void
-nng_ipc_recv(nng_ipc *ipc, nng_aio *aio)
-{
- nni_ipc_conn_recv((void *) ipc, aio);
-}
-
-int
-nng_ipc_setopt(nng_ipc *ipc, const char *name, const void *val, size_t sz)
-{
- return (
- nni_ipc_conn_setopt((void *) ipc, name, val, sz, NNI_TYPE_OPAQUE));
-}
-
-int
-nng_ipc_getopt(nng_ipc *ipc, const char *name, void *val, size_t *szp)
-{
- return (nni_ipc_conn_getopt(
- (void *) ipc, name, val, szp, NNI_TYPE_OPAQUE));
-}
-
-int
-nng_ipc_dialer_alloc(nng_ipc_dialer **dp)
-{
- nni_ipc_dialer *d;
- int rv;
-
- if ((rv = nni_init()) != 0) {
- return (rv);
- }
- if ((rv = nni_ipc_dialer_init(&d)) == 0) {
- *dp = (void *) d;
- }
- return (rv);
-}
-
-void
-nng_ipc_dialer_close(nng_ipc_dialer *d)
-{
- nni_ipc_dialer_close((void *) d);
-}
-
-void
-nng_ipc_dialer_free(nng_ipc_dialer *d)
-{
- nni_ipc_dialer_fini((void *) d);
-}
-
-void
-nng_ipc_dialer_dial(nng_ipc_dialer *d, const nng_sockaddr *sa, nng_aio *aio)
-{
- nni_ipc_dialer_dial((void *) d, sa, aio);
-}
-
-int
-nng_ipc_listener_alloc(nng_ipc_listener **lp)
-{
- nni_ipc_listener *l;
- int rv;
-
- if ((rv = nni_init()) != 0) {
- return (rv);
- }
- if ((rv = nni_ipc_listener_init(&l)) == 0) {
- *lp = (void *) l;
- }
- return (rv);
-}
-
-void
-nng_ipc_listener_close(nng_ipc_listener *l)
-{
- nni_ipc_listener_close((void *) l);
-}
-
-void
-nng_ipc_listener_free(nng_ipc_listener *l)
-{
- nni_ipc_listener_fini((void *) l);
-}
-
-int
-nng_ipc_listener_listen(nng_ipc_listener *l, const nng_sockaddr *sa)
-{
- return (nni_ipc_listener_listen((void *) l, sa));
-}
-
-void
-nng_ipc_listener_accept(nng_ipc_listener *l, nng_aio *aio)
-{
- nni_ipc_listener_accept((void *) l, aio);
-}
diff --git a/src/supplemental/tcp/CMakeLists.txt b/src/supplemental/tcp/CMakeLists.txt
index ef82b098..09f917f8 100644
--- a/src/supplemental/tcp/CMakeLists.txt
+++ b/src/supplemental/tcp/CMakeLists.txt
@@ -1,6 +1,6 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
@@ -8,8 +8,6 @@
# found online at https://opensource.org/licenses/MIT.
#
-set(_SRCS supplemental/tcp/tcp.c
- ${PROJECT_SOURCE_DIR}/include/nng/supplemental/tcp/tcp.h
-)
+set(_SRCS supplemental/tcp/tcp.c)
set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
diff --git a/src/supplemental/tcp/tcp.c b/src/supplemental/tcp/tcp.c
index b8410b16..3ec396b8 100644
--- a/src/supplemental/tcp/tcp.c
+++ b/src/supplemental/tcp/tcp.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -11,144 +11,428 @@
#include <stddef.h>
#include <stdint.h>
+#include <string.h>
#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
#include "core/nng_impl.h"
+#include "core/tcp.h"
-// This is our "public" TCP API. This allows applications to access
-// basic TCP functions, using our AIO framework. Most applications will
-// not need this.
+typedef struct {
+ nng_stream_dialer ops;
+ char * host;
+ char * port;
+ int af; // address family
+ bool closed;
+ nng_sockaddr sa;
+ nni_tcp_dialer * d; // platform dialer implementation
+ nni_aio * resaio; // resolver aio
+ nni_aio * conaio; // platform connection aio
+ nni_list resaios;
+ nni_list conaios;
+ nni_mtx mtx;
+} tcp_dialer;
-// We treat nng_tcp as nni_tcp_conn, nng_tcp_dialer as nni_tcp_dialer,
-// and nng_tcp_listener as nni_tcp_listener. We cast through void to
-// provide isolation of the names in a way that makes the compiler happy.
-// It turns out we can pretty much just wrap the platform API for TCP that
-// we have already created.
-
-void
-nng_tcp_close(nng_tcp *tcp)
+static void
+tcp_dial_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_tcp_conn_close((void *) tcp);
-}
+ tcp_dialer *d = arg;
-void
-nng_tcp_free(nng_tcp *tcp)
-{
- nni_tcp_conn_fini((void *) tcp);
+ nni_mtx_lock(&d->mtx);
+ if (nni_aio_list_active(aio)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, rv);
+
+ if (nni_list_empty(&d->conaios)) {
+ nni_aio_abort(d->conaio, NNG_ECANCELED);
+ }
+ if (nni_list_empty(&d->resaios)) {
+ nni_aio_abort(d->resaio, NNG_ECANCELED);
+ }
+ }
+ nni_mtx_unlock(&d->mtx);
}
-void
-nng_tcp_send(nng_tcp *tcp, nng_aio *aio)
+static void
+tcp_dial_res_cb(void *arg)
{
- nni_tcp_conn_send((void *) tcp, aio);
+ tcp_dialer *d = arg;
+ nni_aio * aio;
+ int rv;
+
+ nni_mtx_lock(&d->mtx);
+ if (d->closed || ((aio = nni_list_first(&d->resaios)) == NULL)) {
+ // ignore this.
+ while ((aio = nni_list_first(&d->resaios)) != NULL) {
+ nni_list_remove(&d->resaios, aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+ nni_mtx_unlock(&d->mtx);
+ return;
+ }
+
+ nni_list_remove(&d->resaios, aio);
+
+ if ((rv = nni_aio_result(d->resaio)) != 0) {
+ nni_aio_finish_error(aio, rv);
+ } else {
+ nng_sockaddr sa;
+ nni_aio_get_sockaddr(d->resaio, &sa);
+ nni_aio_set_sockaddr(aio, &sa);
+ nni_list_append(&d->conaios, aio);
+ if (nni_list_first(&d->conaios) == aio) {
+ nni_aio_set_sockaddr(d->conaio, &sa);
+ nni_tcp_dial(d->d, d->conaio);
+ }
+ }
+
+ if (!nni_list_empty(&d->resaios)) {
+ nni_tcp_resolv(d->host, d->port, d->af, 0, d->resaio);
+ }
+ nni_mtx_unlock(&d->mtx);
}
-void
-nng_tcp_recv(nng_tcp *tcp, nng_aio *aio)
+static void
+tcp_dial_con_cb(void *arg)
{
- nni_tcp_conn_recv((void *) tcp, aio);
+ tcp_dialer *d = arg;
+ nng_aio * aio;
+ int rv;
+
+ nni_mtx_lock(&d->mtx);
+ rv = nni_aio_result(d->conaio);
+ if ((d->closed) || ((aio = nni_list_first(&d->conaios)) == NULL)) {
+ if (rv == 0) {
+ // Make sure we discard the underlying connection.
+ nng_stream_free(nni_aio_get_output(d->conaio, 0));
+ nni_aio_set_output(d->conaio, 0, NULL);
+ }
+ nni_mtx_unlock(&d->mtx);
+ return;
+ }
+ nni_list_remove(&d->conaios, aio);
+ if (rv != 0) {
+ nni_aio_finish_error(aio, rv);
+ } else {
+ nni_aio_set_output(aio, 0, nni_aio_get_output(d->conaio, 0));
+ nni_aio_finish(aio, 0, 0);
+ }
+
+ if ((aio = nni_list_first(&d->conaios)) != NULL) {
+ nng_sockaddr sa;
+ nni_aio_get_sockaddr(aio, &sa);
+ nni_aio_set_sockaddr(d->conaio, &sa);
+ nni_tcp_dial(d->d, d->conaio);
+ }
+ nni_mtx_unlock(&d->mtx);
}
-int
-nng_tcp_getopt(nng_tcp *tcp, const char *name, void *buf, size_t *szp)
+static void
+tcp_dialer_close(void *arg)
{
- return (nni_tcp_conn_getopt(
- (void *) tcp, name, buf, szp, NNI_TYPE_OPAQUE));
+ tcp_dialer *d = arg;
+ nni_aio * aio;
+ nni_mtx_lock(&d->mtx);
+ d->closed = true;
+ while ((aio = nni_list_first(&d->resaios)) != NULL) {
+ nni_list_remove(&d->resaios, aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+ while ((aio = nni_list_first(&d->conaios)) != NULL) {
+ nni_list_remove(&d->conaios, aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+ nni_tcp_dialer_close(d->d);
+ nni_mtx_unlock(&d->mtx);
}
-int
-nng_tcp_setopt(nng_tcp *tcp, const char *name, const void *buf, size_t sz)
+static void
+tcp_dialer_free(void *arg)
{
- return (
- nni_tcp_conn_setopt((void *) tcp, name, buf, sz, NNI_TYPE_OPAQUE));
+ tcp_dialer *d = arg;
+
+ if (d == NULL) {
+ return;
+ }
+
+ if (d->d != NULL) {
+ nni_tcp_dialer_close(d->d);
+ nni_tcp_dialer_fini(d->d);
+ }
+ nni_strfree(d->host);
+ nni_strfree(d->port);
+ nni_aio_fini(d->resaio);
+ nni_aio_fini(d->conaio);
+ nni_mtx_fini(&d->mtx);
+ NNI_FREE_STRUCT(d);
}
-int
-nng_tcp_dialer_alloc(nng_tcp_dialer **dp)
+static void
+tcp_dialer_dial(void *arg, nng_aio *aio)
{
- nni_tcp_dialer *d;
- int rv;
-
- if ((rv = nni_init()) != 0) {
- return (rv);
+ tcp_dialer *d = arg;
+ int rv;
+ if (nni_aio_begin(aio) != 0) {
+ return;
+ }
+ nni_mtx_lock(&d->mtx);
+ if (d->closed) {
+ nni_mtx_unlock(&d->mtx);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ return;
+ }
+ if ((rv = nni_aio_schedule(aio, tcp_dial_cancel, d)) != 0) {
+ nni_mtx_unlock(&d->mtx);
+ nni_aio_finish_error(aio, rv);
+ return;
}
- if ((rv = nni_tcp_dialer_init(&d)) == 0) {
- *dp = (void *) d;
+ if (d->host != NULL) {
+ nni_list_append(&d->resaios, aio);
+ if (nni_list_first(&d->resaios) == aio) {
+ nni_tcp_resolv(d->host, d->port, d->af, 0, d->resaio);
+ }
+ } else {
+ nni_list_append(&d->conaios, aio);
+ if (nni_list_first(&d->conaios) == aio) {
+ nni_aio_set_sockaddr(d->conaio, &d->sa);
+ nni_tcp_dial(d->d, d->conaio);
+ }
}
- return (rv);
+ nni_mtx_unlock(&d->mtx);
}
-void
-nng_tcp_dialer_close(nng_tcp_dialer *d)
+static int
+tcp_dialer_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- nni_tcp_dialer_close((void *) d);
+ tcp_dialer *d = arg;
+ return (nni_tcp_dialer_getopt(d->d, name, buf, szp, t));
}
-void
-nng_tcp_dialer_free(nng_tcp_dialer *d)
+static int
+tcp_dialer_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
- nni_tcp_dialer_fini((void *) d);
+ tcp_dialer *d = arg;
+ return (nni_tcp_dialer_setopt(d->d, name, buf, sz, t));
}
-void
-nng_tcp_dialer_dial(nng_tcp_dialer *d, const nng_sockaddr *sa, nng_aio *aio)
+static int
+tcp_dialer_alloc(tcp_dialer **dp)
{
- nni_tcp_dialer_dial((void *) d, sa, aio);
+ int rv;
+ tcp_dialer *d;
+
+ if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ nni_mtx_init(&d->mtx);
+ nni_aio_list_init(&d->resaios);
+ nni_aio_list_init(&d->conaios);
+
+ if (((rv = nni_aio_init(&d->resaio, tcp_dial_res_cb, d)) != 0) ||
+ ((rv = nni_aio_init(&d->conaio, tcp_dial_con_cb, d)) != 0) ||
+ ((rv = nni_tcp_dialer_init(&d->d)) != 0)) {
+ tcp_dialer_free(d);
+ return (rv);
+ }
+
+ d->ops.sd_close = tcp_dialer_close;
+ d->ops.sd_free = tcp_dialer_free;
+ d->ops.sd_dial = tcp_dialer_dial;
+ d->ops.sd_getx = tcp_dialer_getx;
+ d->ops.sd_setx = tcp_dialer_setx;
+
+ *dp = d;
+ return (0);
}
int
-nng_tcp_listener_alloc(nng_tcp_listener **lp)
+nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
{
- nni_tcp_listener *l;
- int rv;
+ tcp_dialer *d;
+ int rv;
+ const char *p;
if ((rv = nni_init()) != 0) {
return (rv);
}
- if ((rv = nni_tcp_listener_init(&l)) == 0) {
- *lp = (void *) l;
+
+ if ((rv = tcp_dialer_alloc(&d)) != 0) {
+ return (rv);
}
- return (rv);
+
+ if (((p = url->u_port) == NULL) || (strlen(p) == 0)) {
+ p = nni_url_default_port(url->u_scheme);
+ }
+
+ if ((strlen(p) == 0) || (strlen(url->u_hostname) == 0)) {
+ // Dialer needs both a destination hostname and port.
+ tcp_dialer_free(d);
+ return (NNG_EADDRINVAL);
+ }
+
+ if (strchr(url->u_scheme, '4') != NULL) {
+ d->af = NNG_AF_INET;
+ } else if (strchr(url->u_scheme, '6') != NULL) {
+ d->af = NNG_AF_INET6;
+ } else {
+ d->af = NNG_AF_UNSPEC;
+ }
+
+ if (((d->host = nng_strdup(url->u_hostname)) == NULL) ||
+ ((d->port = nng_strdup(p)) == NULL)) {
+ tcp_dialer_free(d);
+ return (NNG_ENOMEM);
+ }
+
+ *dp = (void *) d;
+ return (0);
}
-void
-nng_tcp_listener_close(nng_tcp_listener *l)
+typedef struct {
+ nng_stream_listener ops;
+ nni_tcp_listener * l;
+ nng_sockaddr sa;
+} tcp_listener;
+
+static void
+tcp_listener_close(void *arg)
{
- nni_tcp_listener_close((void *) l);
+ tcp_listener *l = arg;
+ nni_tcp_listener_close(l->l);
}
-void
-nng_tcp_listener_free(nng_tcp_listener *l)
+static void
+tcp_listener_free(void *arg)
{
- nni_tcp_listener_fini((void *) l);
+ tcp_listener *l = arg;
+ nni_tcp_listener_fini(l->l);
+ NNI_FREE_STRUCT(l);
}
-int
-nng_tcp_listener_listen(nng_tcp_listener *l, const nng_sockaddr *sa)
+static int
+tcp_listener_listen(void *arg)
+{
+ tcp_listener *l = arg;
+ return (nni_tcp_listener_listen(l->l, &l->sa));
+}
+
+static void
+tcp_listener_accept(void *arg, nng_aio *aio)
{
- return (nni_tcp_listener_listen((void *) l, sa));
+ tcp_listener *l = arg;
+ nni_tcp_listener_accept(l->l, aio);
}
-void
-nng_tcp_listener_accept(nng_tcp_listener *l, nng_aio *aio)
+static int
+tcp_listener_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- nni_tcp_listener_accept((void *) l, aio);
+ tcp_listener *l = arg;
+ return (nni_tcp_listener_getopt(l->l, name, buf, szp, t));
+}
+
+static int
+tcp_listener_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
+{
+ tcp_listener *l = arg;
+ return (nni_tcp_listener_setopt(l->l, name, buf, sz, t));
+}
+
+static int
+tcp_listener_alloc_addr(nng_stream_listener **lp, const nng_sockaddr *sa)
+{
+ tcp_listener *l;
+ int rv;
+
+ if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ if ((rv = nni_tcp_listener_init(&l->l)) != 0) {
+ NNI_FREE_STRUCT(l);
+ return (rv);
+ }
+ l->sa = *sa;
+
+ l->ops.sl_free = tcp_listener_free;
+ l->ops.sl_close = tcp_listener_close;
+ l->ops.sl_listen = tcp_listener_listen;
+ l->ops.sl_accept = tcp_listener_accept;
+ l->ops.sl_getx = tcp_listener_getx;
+ l->ops.sl_setx = tcp_listener_setx;
+
+ *lp = (void *) l;
+ return (0);
}
int
-nng_tcp_listener_getopt(
- nng_tcp_listener *l, const char *name, void *buf, size_t *szp)
+nni_tcp_listener_alloc(nng_stream_listener **lp, const nng_url *url)
{
- return (nni_tcp_listener_getopt(
- (void *) l, name, buf, szp, NNI_TYPE_OPAQUE));
+ nni_aio * aio;
+ int af;
+ int rv;
+ nng_sockaddr sa;
+ const char * h;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+ if (strchr(url->u_scheme, '4') != NULL) {
+ af = NNG_AF_INET;
+ } else if (strchr(url->u_scheme, '6') != NULL) {
+ af = NNG_AF_INET6;
+ } else {
+ af = NNG_AF_UNSPEC;
+ }
+
+ if ((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) {
+ return (rv);
+ }
+
+ h = url->u_hostname;
+
+ // Wildcard special case, which means bind to INADDR_ANY.
+ if ((h != NULL) && ((strcmp(h, "*") == 0) || (strlen(h) == 0))) {
+ h = NULL;
+ }
+ nni_tcp_resolv(h, url->u_port, af, 1, aio);
+ nni_aio_wait(aio);
+
+ if ((rv = nni_aio_result(aio)) != 0) {
+ nni_aio_fini(aio);
+ return (rv);
+ }
+ nni_aio_get_sockaddr(aio, &sa);
+ nni_aio_fini(aio);
+
+ return (tcp_listener_alloc_addr(lp, &sa));
}
+static int
+tcp_check_bool(const void *val, size_t sz, nni_type t)
+{
+ return (nni_copyin_bool(NULL, val, sz, t));
+}
+
+static const nni_chkoption tcp_chkopts[] = {
+ {
+ .o_name = NNG_OPT_TCP_KEEPALIVE,
+ .o_check = tcp_check_bool,
+ },
+ {
+ .o_name = NNG_OPT_TCP_NODELAY,
+ .o_check = tcp_check_bool,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
int
-nng_tcp_listener_setopt(
- nng_tcp_listener *l, const char *name, const void *buf, size_t sz)
+nni_tcp_checkopt(const char *name, const void *data, size_t sz, nni_type t)
{
- return (nni_tcp_listener_setopt(
- (void *) l, name, buf, sz, NNI_TYPE_OPAQUE));
-} \ No newline at end of file
+ return (nni_chkopt(tcp_chkopts, name, data, sz, t));
+}
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);
}
diff --git a/src/supplemental/websocket/CMakeLists.txt b/src/supplemental/websocket/CMakeLists.txt
index 22ee955d..3b102c80 100644
--- a/src/supplemental/websocket/CMakeLists.txt
+++ b/src/supplemental/websocket/CMakeLists.txt
@@ -12,5 +12,7 @@ if (NNG_SUPP_WEBSOCKET)
set(_SRCS
supplemental/websocket/websocket.c
supplemental/websocket/websocket.h)
+else()
+ set(_SRCS supplemental/websocket/stubs.c)
endif()
set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
diff --git a/src/supplemental/websocket/stub.c b/src/supplemental/websocket/stub.c
new file mode 100644
index 00000000..94e7f1b5
--- /dev/null
+++ b/src/supplemental/websocket/stub.c
@@ -0,0 +1,40 @@
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// 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 "core/nng_impl.h"
+
+// This stub file exists to support configuration of the stream subsystem
+// when websocket support is unconfigured.
+
+int
+nni_ws_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
+{
+ NNI_ARG_UNUSED(dp);
+ NNI_ARG_UNUSED(url);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_ws_listener_alloc(nng_stream_listener **lp, const nng_url *url)
+{
+ NNI_ARG_UNUSED(lp);
+ NNI_ARG_UNUSED(url);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_ws_checkopt(const char *name, const void *data, size_t sz, nni_type t)
+{
+ NNI_ARG_UNUSED(name);
+ NNI_ARG_UNUSED(data);
+ NNI_ARG_UNUSED(sz);
+ NNI_ARG_UNUSED(t);
+ return (NNG_ENOTSUP);
+}
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index 3d3a68cb..4cecf430 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -18,11 +18,25 @@
#include "supplemental/http/http_api.h"
#include "supplemental/sha1/sha1.h"
+#include <nng/transport/ws/websocket.h>
+
#include "websocket.h"
+// This should be removed or handled differently in the future.
+typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *);
+
+// We have chosen to be a bit more stringent in the size of the frames that
+// we send, while we more generously allow larger incoming frames. These
+// may be tuned by options.
+#define WS_DEF_RECVMAX (1U << 20) // 1MB Message limit (message mode only)
+#define WS_DEF_MAXRXFRAME (1U << 20) // 1MB Frame size (recv)
+#define WS_DEF_MAXTXFRAME (1U << 16) // 64KB Frame size (send)
+
+// Alias for checking the prefix of a string.
+#define startswith(s, t) (strncmp(s, t, strlen(t)) == 0)
+
// Pre-defined types for some prototypes. These are from other subsystems.
typedef struct ws_frame ws_frame;
-typedef struct ws_msg ws_msg;
typedef struct ws_header {
nni_list_node node;
@@ -31,17 +45,20 @@ typedef struct ws_header {
} ws_header;
struct nni_ws {
+ nng_stream ops;
nni_list_node node;
nni_reap_item reap;
bool server;
bool closed;
bool ready;
bool wclose;
+ bool isstream;
+ bool inmsg;
nni_mtx mtx;
- nni_list txmsgs;
- nni_list rxmsgs;
nni_list sendq;
nni_list recvq;
+ nni_list txq;
+ nni_list rxq;
ws_frame * txframe;
ws_frame * rxframe;
nni_aio * txaio; // physical aios
@@ -57,26 +74,31 @@ struct nni_ws {
char * reshdrs;
size_t maxframe;
size_t fragsize;
+ size_t recvmax; // largest message size
nni_ws_listener *listener;
nni_ws_dialer * dialer;
};
struct nni_ws_listener {
- nni_http_server * server;
- char * proto;
- nni_mtx mtx;
- nni_cv cv;
- nni_list pend;
- nni_list reply;
- nni_list aios;
- nni_url * url;
- bool started;
- bool closed;
- nni_http_handler * handler;
- nni_ws_listen_hook hookfn;
- void * hookarg;
- nni_list headers; // response headers
- size_t maxframe;
+ nng_stream_listener ops;
+ nni_http_server * server;
+ char * proto;
+ nni_mtx mtx;
+ nni_cv cv;
+ nni_list pend;
+ nni_list reply;
+ nni_list aios;
+ nng_url * url;
+ bool started;
+ bool closed;
+ bool isstream;
+ nni_http_handler * handler;
+ nni_ws_listen_hook hookfn;
+ void * hookarg;
+ nni_list headers; // response headers
+ size_t maxframe;
+ size_t fragsize;
+ size_t recvmax; // largest message size
};
// The dialer tracks user aios in two lists. The first list is for aios
@@ -86,18 +108,21 @@ struct nni_ws_listener {
// completion of an earlier connection. (We don't want to establish
// requests when we already have connects negotiating.)
struct nni_ws_dialer {
- nni_http_req * req;
- nni_http_res * res;
- nni_http_client *client;
- nni_mtx mtx;
- nni_cv cv;
- char * proto;
- nni_url * url;
- nni_list wspend; // ws structures still negotiating
- bool closed;
- nng_sockaddr sa;
- nni_list headers; // request headers
- size_t maxframe;
+ nng_stream_dialer ops;
+ nni_http_req * req;
+ nni_http_res * res;
+ nni_http_client * client;
+ nni_mtx mtx;
+ nni_cv cv;
+ char * proto;
+ nng_url * url;
+ nni_list wspend; // ws structures still negotiating
+ bool closed;
+ bool isstream;
+ nni_list headers; // request headers
+ size_t maxframe;
+ size_t fragsize;
+ size_t recvmax;
};
typedef enum ws_type {
@@ -133,16 +158,7 @@ struct ws_frame {
bool masked;
size_t bufsz; // allocated size
uint8_t * buf;
- ws_msg * wmsg;
-};
-
-struct ws_msg {
- nni_list frames;
- nni_list_node node;
- nni_ws * ws;
- nni_aio * aio;
- uint8_t * buf;
- size_t bufsz;
+ nng_aio * aio;
};
static void ws_send_close(nni_ws *ws, uint16_t code);
@@ -150,6 +166,127 @@ static void ws_conn_cb(void *);
static void ws_close_cb(void *);
static void ws_read_cb(void *);
static void ws_write_cb(void *);
+static void ws_close_error(nni_ws *ws, uint16_t code);
+
+static void ws_str_free(void *);
+static void ws_str_close(void *);
+static void ws_str_send(void *, nng_aio *);
+static void ws_str_recv(void *, nng_aio *);
+static int ws_str_getx(void *, const char *, void *, size_t *, nni_type);
+static int ws_str_setx(void *, const char *, const void *, size_t, nni_type);
+
+static void ws_listener_close(void *);
+static void ws_listener_free(void *);
+
+static int
+ws_check_string(const void *v, size_t sz, nni_opt_type t)
+{
+ if ((t != NNI_TYPE_OPAQUE) && (t != NNI_TYPE_STRING)) {
+ return (NNG_EBADTYPE);
+ }
+ if (nni_strnlen(v, sz) >= sz) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+static int
+ws_set_header_ext(nni_list *l, const char *n, const char *v, bool strip_dups)
+{
+ ws_header *hdr;
+ char * nv;
+
+ if ((nv = nni_strdup(v)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ if (strip_dups) {
+ NNI_LIST_FOREACH (l, hdr) {
+ if (nni_strcasecmp(hdr->name, n) == 0) {
+ nni_strfree(hdr->value);
+ hdr->value = nv;
+ return (0);
+ }
+ }
+ }
+
+ if ((hdr = NNI_ALLOC_STRUCT(hdr)) == NULL) {
+ nni_strfree(nv);
+ return (NNG_ENOMEM);
+ }
+ if ((hdr->name = nni_strdup(n)) == NULL) {
+ nni_strfree(nv);
+ NNI_FREE_STRUCT(hdr);
+ return (NNG_ENOMEM);
+ }
+ hdr->value = nv;
+ nni_list_append(l, hdr);
+ return (0);
+}
+
+static int
+ws_set_header(nni_list *l, const char *n, const char *v)
+{
+ return (ws_set_header_ext(l, n, v, true));
+}
+
+static int
+ws_set_headers(nni_list *l, const char *str)
+{
+ char * dupstr;
+ size_t duplen;
+ char * n;
+ char * v;
+ char * nl;
+ int rv;
+
+ if ((dupstr = nni_strdup(str)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ duplen = strlen(dupstr) + 1; // so we can free it later
+
+ n = dupstr;
+ for (;;) {
+ if ((v = strchr(n, ':')) == NULL) {
+ // Note that this also means that if
+ // a bare word is present, we ignore it.
+ break;
+ }
+ *v = '\0';
+ v++;
+ while (*v == ' ') {
+ // Skip leading whitespace. Not strictly
+ // necessary, but still a good idea.
+ v++;
+ }
+ nl = v;
+ // Find the end of the line -- should be CRLF, but can
+ // also be unterminated or just LF if user
+ while ((*nl != '\0') && (*nl != '\r') && (*nl != '\n')) {
+ nl++;
+ }
+ while ((*nl == '\r') || (*nl == '\n')) {
+ *nl = '\0';
+ nl++;
+ }
+
+ // Note that this can lead to a partial failure. As this
+ // is most likely ENOMEM, don't worry too much about it.
+ // This method does *not* eliminate duplicates.
+ if ((rv = ws_set_header_ext(l, n, v, false)) != 0) {
+ goto done;
+ }
+
+ // Advance to the next name.
+ n = nl;
+ }
+
+ rv = 0;
+
+done:
+ nni_free(dupstr, duplen);
+ return (rv);
+}
// This looks, case independently for a word in a list, which is either
// space or comma separated.
@@ -204,30 +341,13 @@ ws_make_accept(const char *key, char *accept)
static void
ws_frame_fini(ws_frame *frame)
{
- if (frame->bufsz) {
+ if (frame->bufsz != 0) {
nni_free(frame->buf, frame->bufsz);
}
NNI_FREE_STRUCT(frame);
}
static void
-ws_msg_fini(ws_msg *wm)
-{
- ws_frame *frame;
-
- NNI_ASSERT(!nni_list_node_active(&wm->node));
- while ((frame = nni_list_first(&wm->frames)) != NULL) {
- nni_list_remove(&wm->frames, frame);
- ws_frame_fini(frame);
- }
- if (wm->bufsz != 0) {
- nni_free(wm->buf, wm->bufsz);
- }
-
- NNI_FREE_STRUCT(wm);
-}
-
-static void
ws_mask_frame(ws_frame *frame)
{
uint32_t r;
@@ -263,31 +383,19 @@ ws_unmask_frame(ws_frame *frame)
static int
ws_msg_init_control(
- ws_msg **wmp, nni_ws *ws, uint8_t op, const uint8_t *buf, size_t len)
+ ws_frame **framep, nni_ws *ws, uint8_t op, const uint8_t *buf, size_t len)
{
- ws_msg * wm;
ws_frame *frame;
if (len > 125) {
return (NNG_EINVAL);
}
- if ((wm = NNI_ALLOC_STRUCT(wm)) == NULL) {
- return (NNG_ENOMEM);
- }
- wm->buf = NULL;
- wm->bufsz = 0;
-
if ((frame = NNI_ALLOC_STRUCT(frame)) == NULL) {
- ws_msg_fini(wm);
return (NNG_ENOMEM);
}
- NNI_LIST_INIT(&wm->frames, ws_frame, node);
memcpy(frame->sdata, buf, len);
-
- nni_list_append(&wm->frames, frame);
- frame->wmsg = wm;
frame->len = len;
frame->final = true;
frame->op = op;
@@ -303,114 +411,100 @@ ws_msg_init_control(
ws_mask_frame(frame);
}
- wm->aio = NULL;
- wm->ws = ws;
- *wmp = wm;
+ *framep = frame;
return (0);
}
static int
-ws_msg_init_tx(ws_msg **wmp, nni_ws *ws, nni_msg *msg, nni_aio *aio)
+ws_frame_prep_tx(nni_ws *ws, ws_frame *frame)
{
- ws_msg * wm;
+ nng_aio *aio = frame->aio;
+ nni_iov *iov;
+ unsigned niov;
size_t len;
- size_t maxfrag = ws->fragsize; // make this tunable. (1MB default)
uint8_t *buf;
- uint8_t op;
-
- if ((wm = NNI_ALLOC_STRUCT(wm)) == NULL) {
- return (NNG_ENOMEM);
- }
- NNI_LIST_INIT(&wm->frames, ws_frame, node);
-
- len = nni_msg_len(msg) + nni_msg_header_len(msg);
- wm->bufsz = len;
- if ((wm->buf = nni_alloc(len)) == NULL) {
- NNI_FREE_STRUCT(wm);
- return (NNG_ENOMEM);
- }
- buf = wm->buf;
- memcpy(buf, nni_msg_header(msg), nni_msg_header_len(msg));
- memcpy(buf + nni_msg_header_len(msg), nni_msg_body(msg),
- nni_msg_len(msg));
-
- op = WS_BINARY; // to start -- no support for sending TEXT frames
-
- // do ... while because we want at least one frame (even for empty
- // messages.) Headers get their own frame, if present. Best bet
- // is to try not to have a header when coming here.
- do {
- ws_frame *frame;
- if ((frame = NNI_ALLOC_STRUCT(frame)) == NULL) {
- ws_msg_fini(wm);
+ // Figure out how much we need for the entire aio.
+ frame->len = 0;
+ nni_aio_get_iov(aio, &niov, &iov);
+ for (unsigned i = 0; i < niov; i++) {
+ frame->len += iov[i].iov_len;
+ }
+
+ if ((frame->len > ws->fragsize) && (ws->fragsize > 0)) {
+ // Limit it to a single frame per policy (fragsize), as needed.
+ frame->len = ws->fragsize;
+ // For stream mode, we constrain ourselves to one frame
+ // per message. Submitter may see a partial transmit, and
+ // should resubmit as needed. For message mode, we will
+ // continue to resubmit.
+ frame->final = ws->isstream ? true : false;
+ } else {
+ // It all fits in this frame (which might not be the first),
+ // so we're done.
+ frame->final = true;
+ }
+ // Potentially allocate space for the data if we need to.
+ // Note that an empty message is legal.
+ if ((frame->bufsz < frame->len) && (frame->len > 0)) {
+ frame->buf = nni_alloc(frame->len);
+ if (frame->buf == NULL) {
return (NNG_ENOMEM);
}
- nni_list_append(&wm->frames, frame);
- frame->wmsg = wm;
- frame->len = len > maxfrag ? maxfrag : len;
- frame->buf = buf;
- frame->op = op;
-
- buf += frame->len;
- len -= frame->len;
- op = WS_CONT;
-
- if (len == 0) {
- frame->final = true;
- }
- frame->head[0] = frame->op;
- frame->hlen = 2;
- if (frame->final) {
- frame->head[0] |= 0x80; // final frame bit
- }
- if (frame->len < 126) {
- frame->head[1] = frame->len & 0x7f;
- } else if (frame->len < 65536) {
- frame->head[1] = 126;
- NNI_PUT16(frame->head + 2, (frame->len & 0xffff));
- frame->hlen += 2;
- } else {
- frame->head[1] = 127;
- NNI_PUT64(frame->head + 2, (uint64_t) frame->len);
- frame->hlen += 8;
- }
+ }
+ buf = frame->buf;
- if (ws->server) {
- frame->masked = false;
- } else {
- ws_mask_frame(frame);
+ // Now copy the data into the frame.
+ len = frame->len;
+ while (len != 0) {
+ size_t n = len;
+ if (n > iov->iov_len) {
+ n = iov->iov_len;
}
+ memcpy(buf, iov->iov_buf, n);
+ iov++;
+ len -= n;
+ buf += n;
+ }
- } while (len);
-
- wm->aio = aio;
- wm->ws = ws;
- *wmp = wm;
- return (0);
-}
+ if (nni_aio_count(aio) == 0) {
+ // This is the first frame.
+ frame->op = WS_BINARY;
+ } else {
+ frame->op = WS_CONT;
+ }
-static int
-ws_msg_init_rx(ws_msg **wmp, nni_ws *ws, nni_aio *aio)
-{
- ws_msg *wm;
+ // Populate the frame header.
+ frame->head[0] = frame->op;
+ frame->hlen = 2;
+ if (frame->final) {
+ frame->head[0] |= 0x80; // final frame bit
+ }
+ if (frame->len < 126) {
+ frame->head[1] = frame->len & 0x7f;
+ } else if (frame->len < 65536) {
+ frame->head[1] = 126;
+ NNI_PUT16(frame->head + 2, (frame->len & 0xffff));
+ frame->hlen += 2;
+ } else {
+ frame->head[1] = 127;
+ NNI_PUT64(frame->head + 2, (uint64_t) frame->len);
+ frame->hlen += 8;
+ }
- if ((wm = NNI_ALLOC_STRUCT(wm)) == NULL) {
- return (NNG_ENOMEM);
+ // If we are on the client, then we need to mask the frame.
+ frame->masked = false;
+ if (!ws->server) {
+ ws_mask_frame(frame);
}
- NNI_LIST_INIT(&wm->frames, ws_frame, node);
- wm->aio = aio;
- wm->ws = ws;
- *wmp = wm;
return (0);
}
static void
ws_close_cb(void *arg)
{
- nni_ws * ws = arg;
- ws_msg * wm;
- nni_aio *aio;
+ nni_ws * ws = arg;
+ ws_frame *frame;
nni_aio_close(ws->txaio);
nni_aio_close(ws->rxaio);
@@ -422,31 +516,13 @@ ws_close_cb(void *arg)
nni_http_conn_close(ws->http);
- // This list (receive) should be empty.
- while ((wm = nni_list_first(&ws->rxmsgs)) != NULL) {
- nni_list_remove(&ws->rxmsgs, wm);
- if ((aio = wm->aio) != NULL) {
- wm->aio = NULL;
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- }
- ws_msg_fini(wm);
- }
-
- while ((wm = nni_list_first(&ws->txmsgs)) != NULL) {
- nni_list_remove(&ws->txmsgs, wm);
- if ((aio = wm->aio) != NULL) {
- wm->aio = NULL;
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
+ while ((frame = nni_list_first(&ws->txq)) != NULL) {
+ nni_list_remove(&ws->txq, frame);
+ if (frame->aio != NULL) {
+ nni_aio_list_remove(frame->aio);
+ nni_aio_finish_error(frame->aio, NNG_ECLOSED);
}
- ws_msg_fini(wm);
- }
- ws->txframe = NULL;
-
- if (ws->rxframe != NULL) {
- ws_frame_fini(ws->rxframe);
- ws->rxframe = NULL;
+ ws_frame_fini(frame);
}
// Any txframe should have been killed with its wmsg.
@@ -456,19 +532,13 @@ ws_close_cb(void *arg)
static void
ws_close(nni_ws *ws, uint16_t code)
{
- ws_msg *wm;
+ nng_aio *aio;
// Receive stuff gets aborted always. No further receives
// once we get a close.
- while ((wm = nni_list_first(&ws->rxmsgs)) != NULL) {
- nni_aio *aio;
- nni_list_remove(&ws->rxmsgs, wm);
- if ((aio = wm->aio) != NULL) {
- wm->aio = NULL;
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- }
- ws_msg_fini(wm);
+ while ((aio = nni_list_first(&ws->recvq)) != NULL) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
}
// If were closing "gracefully", then don't abort in-flight
@@ -487,7 +557,6 @@ static void
ws_start_write(nni_ws *ws)
{
ws_frame *frame;
- ws_msg * wm;
nni_iov iov[2];
int niov;
@@ -495,13 +564,11 @@ ws_start_write(nni_ws *ws)
return; // busy
}
- if ((wm = nni_list_first(&ws->txmsgs)) == NULL) {
- // Nothing to send.
- return;
+ if ((frame = nni_list_first(&ws->txq)) == NULL) {
+ return; // nothing to send
}
-
- frame = nni_list_first(&wm->frames);
NNI_ASSERT(frame != NULL);
+ nni_list_remove(&ws->txq, frame);
// Push it out.
ws->txframe = frame;
@@ -534,7 +601,6 @@ ws_write_cb(void *arg)
{
nni_ws * ws = arg;
ws_frame *frame;
- ws_msg * wm;
nni_aio * aio;
int rv;
@@ -545,17 +611,20 @@ ws_write_cb(void *arg)
return;
}
ws->txframe = NULL;
+
if (frame->op == WS_CLOSE) {
// If this was a close frame, we are done.
// No other messages may succeed..
- while ((wm = nni_list_first(&ws->txmsgs)) != NULL) {
- nni_list_remove(&ws->txmsgs, wm);
- if ((aio = wm->aio) != NULL) {
- wm->aio = NULL;
+ ws->txframe = NULL;
+ ws_frame_fini(frame);
+ while ((frame = nni_list_first(&ws->txq)) != NULL) {
+ nni_list_remove(&ws->txq, frame);
+ if ((aio = frame->aio) != NULL) {
+ frame->aio = NULL;
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, NNG_ECLOSED);
+ ws_frame_fini(frame);
}
- ws_msg_fini(wm);
}
if (ws->wclose) {
ws->wclose = false;
@@ -565,54 +634,55 @@ ws_write_cb(void *arg)
return;
}
- wm = frame->wmsg;
- aio = wm->aio;
-
+ aio = frame->aio;
if ((rv = nni_aio_result(ws->txaio)) != 0) {
-
- nni_list_remove(&ws->txmsgs, wm);
- ws_msg_fini(wm);
+ frame->aio = NULL;
if (aio != NULL) {
- wm->aio = NULL;
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
}
-
+ ws_frame_fini(frame);
ws->closed = true;
nni_http_conn_close(ws->http);
nni_mtx_unlock(&ws->mtx);
return;
}
- // good frame, was it the last
- nni_list_remove(&wm->frames, frame);
- ws_frame_fini(frame);
-
- // if we still have more frames to transmit, then schedule it.
- if (!nni_list_empty(&wm->frames)) {
- ws_start_write(ws);
- nni_mtx_unlock(&ws->mtx);
- return;
+ if (aio != NULL) {
+ nni_aio_iov_advance(aio, frame->len);
+ nni_aio_bump_count(aio, frame->len);
+ if (frame->final) {
+ frame->aio = NULL;
+ nni_aio_list_remove(aio);
+ } else {
+ // Clear the aio so that we won't attempt to finish
+ // it outside the lock
+ aio = NULL;
+ }
}
- if (aio != NULL) {
- wm->aio = NULL;
- nni_aio_list_remove(aio);
+ if (frame->final) {
+ ws_frame_fini(frame);
+ } else {
+ // This one cannot fail here, since we only do allocation
+ // at initial scheduling.
+ ws_frame_prep_tx(ws, frame);
+ // Schedule at end. This permits other frames to interleave.
+ nni_list_append(&ws->txq, frame);
}
- nni_list_remove(&ws->txmsgs, wm);
- // Write the next frame.
ws_start_write(ws);
nni_mtx_unlock(&ws->mtx);
- // discard while not holding lock (just deallocations)
- ws_msg_fini(wm);
-
+ // We attempt to finish the operation synchronously, outside the lock.
if (aio != NULL) {
- nng_msg *msg = nni_aio_get_msg(aio);
- nni_aio_set_msg(aio, NULL);
- nni_aio_finish_synch(aio, 0, nni_msg_len(msg));
- nni_msg_free(msg);
+ nni_msg *msg;
+ // Successful send, don't leak the message!
+ if ((msg = nni_aio_get_msg(aio)) != NULL) {
+ nni_aio_set_msg(aio, NULL);
+ nni_msg_free(msg);
+ }
+ nni_aio_finish_synch(aio, 0, nni_aio_count(aio));
}
}
@@ -620,7 +690,6 @@ static void
ws_write_cancel(nni_aio *aio, void *arg, int rv)
{
nni_ws * ws = arg;
- ws_msg * wm;
ws_frame *frame;
// Is this aio active? We can tell by looking at the active tx frame.
@@ -630,17 +699,17 @@ ws_write_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&ws->mtx);
return;
}
- wm = nni_aio_get_prov_extra(aio, 0);
- if (((frame = ws->txframe) != NULL) && (frame->wmsg == wm)) {
+ frame = nni_aio_get_prov_extra(aio, 0);
+ if (frame == ws->txframe) {
nni_aio_abort(ws->txaio, rv);
// We will wait for callback on the txaio to finish aio.
- } else if (nni_list_active(&ws->txmsgs, wm)) {
+ } else {
// If scheduled, just need to remove node and complete it.
- nni_list_remove(&ws->txmsgs, wm);
- wm->aio = NULL;
+ nni_list_remove(&ws->txq, frame);
+ frame->aio = NULL;
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
- ws_msg_fini(wm);
+ ws_frame_fini(frame);
}
nni_mtx_unlock(&ws->mtx);
}
@@ -648,10 +717,10 @@ ws_write_cancel(nni_aio *aio, void *arg, int rv)
static void
ws_send_close(nni_ws *ws, uint16_t code)
{
- ws_msg * wm;
- uint8_t buf[sizeof(uint16_t)];
- int rv;
- nni_aio *aio;
+ ws_frame *frame;
+ uint8_t buf[sizeof(uint16_t)];
+ int rv;
+ nni_aio * aio;
NNI_PUT16(buf, code);
@@ -665,125 +734,45 @@ ws_send_close(nni_ws *ws, uint16_t code)
return;
}
ws->wclose = true;
- rv = ws_msg_init_control(&wm, ws, WS_CLOSE, buf, sizeof(buf));
+ rv = ws_msg_init_control(&frame, ws, WS_CLOSE, buf, sizeof(buf));
if (rv != 0) {
ws->wclose = false;
nni_aio_finish_error(aio, rv);
return;
}
- // Close frames get priority!
if ((rv = nni_aio_schedule(aio, ws_cancel_close, ws)) != 0) {
ws->wclose = false;
nni_aio_finish_error(aio, rv);
+ ws_frame_fini(frame);
return;
}
- nni_list_prepend(&ws->txmsgs, wm);
+ // This gets inserted at the head.
+ nni_list_prepend(&ws->txq, frame);
ws_start_write(ws);
}
static void
ws_send_control(nni_ws *ws, uint8_t op, uint8_t *buf, size_t len)
{
- ws_msg *wm;
+ ws_frame *frame;
// Note that we do not care if this works or not. So no AIO needed.
if ((ws->closed) ||
- (ws_msg_init_control(&wm, ws, op, buf, len) != 0)) {
+ (ws_msg_init_control(&frame, ws, op, buf, len) != 0)) {
return;
}
// Control frames at head of list. (Note that this may preempt
// the close frame or other ping/pong requests. Oh well.)
- nni_list_prepend(&ws->txmsgs, wm);
+ nni_list_prepend(&ws->txq, frame);
ws_start_write(ws);
}
-static const nni_option ws_options[] = {
- {
- .o_name = NULL,
- },
-};
-
-int
-nni_ws_getopt(nni_ws *ws, const char *name, void *buf, size_t *szp, nni_type t)
-{
- int rv;
-
- nni_mtx_lock(&ws->mtx);
- if (ws->closed) {
- nni_mtx_unlock(&ws->mtx);
- return (NNG_ECLOSED);
- }
- rv = nni_http_conn_getopt(ws->http, name, buf, szp, t);
- if (rv == NNG_ENOTSUP) {
- rv = nni_getopt(ws_options, name, ws, buf, szp, t);
- }
- nni_mtx_unlock(&ws->mtx);
- return (rv);
-}
-
-int
-nni_ws_setopt(
- nni_ws *ws, const char *name, const void *buf, size_t sz, nni_type t)
-{
- int rv;
-
- nni_mtx_lock(&ws->mtx);
- if (ws->closed) {
- nni_mtx_unlock(&ws->mtx);
- return (NNG_ECLOSED);
- }
- rv = nni_http_conn_setopt(ws->http, name, buf, sz, t);
- if (rv == NNG_ENOTSUP) {
- rv = nni_setopt(ws_options, name, ws, buf, sz, t);
- }
- nni_mtx_unlock(&ws->mtx);
- return (rv);
-}
-
-void
-nni_ws_send_msg(nni_ws *ws, nni_aio *aio)
-{
- ws_msg * wm;
- nni_msg *msg;
- int rv;
-
- msg = nni_aio_get_msg(aio);
-
- if (nni_aio_begin(aio) != 0) {
- return;
- }
- if ((rv = ws_msg_init_tx(&wm, ws, msg, aio)) != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
-
- nni_mtx_lock(&ws->mtx);
- if (ws->closed) {
- nni_mtx_unlock(&ws->mtx);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- ws_msg_fini(wm);
- return;
- }
- if ((rv = nni_aio_schedule(aio, ws_write_cancel, ws)) != 0) {
- nni_mtx_unlock(&ws->mtx);
- nni_aio_finish_error(aio, rv);
- ws_msg_fini(wm);
- return;
- }
- nni_aio_set_prov_extra(aio, 0, wm);
- nni_list_append(&ws->sendq, aio);
- nni_list_append(&ws->txmsgs, wm);
- ws_start_write(ws);
- nni_mtx_unlock(&ws->mtx);
-}
-
static void
ws_start_read(nni_ws *ws)
{
ws_frame *frame;
- ws_msg * wm;
nni_aio * aio;
nni_iov iov;
@@ -791,18 +780,18 @@ ws_start_read(nni_ws *ws)
return; // already reading or closed
}
- if ((wm = nni_list_first(&ws->rxmsgs)) == NULL) {
- return; // no body expecting a message.
+ // If nobody is waiting for recv, and we already have a data
+ // frame, stop reading. This keeps us from buffering infinitely.
+ if (nni_list_empty(&ws->recvq) && !nni_list_empty(&ws->rxq)) {
+ return;
}
if ((frame = NNI_ALLOC_STRUCT(frame)) == NULL) {
- nni_list_remove(&ws->rxmsgs, wm);
- if ((aio = wm->aio) != NULL) {
- wm->aio = NULL;
+ if ((aio = nni_list_first(&ws->recvq)) != NULL) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, NNG_ENOMEM);
}
- ws_msg_fini(wm);
+ ws_close(ws, WS_CLOSE_INTERNAL);
return;
}
@@ -820,34 +809,143 @@ ws_start_read(nni_ws *ws)
}
static void
-ws_read_frame_cb(nni_ws *ws, ws_frame *frame, ws_msg **wmp, nni_aio **aiop)
+ws_read_finish_str(nni_ws *ws)
{
- ws_msg *wm = nni_list_first(&ws->rxmsgs);
+ for (;;) {
+ nni_aio * aio;
+ nni_iov * iov;
+ unsigned niov;
+ ws_frame *frame;
- switch (frame->op) {
- case WS_CONT:
- if (wm == NULL) {
- ws_close(ws, WS_CLOSE_GOING_AWAY);
+ if ((aio = nni_list_first(&ws->recvq)) == NULL) {
return;
}
- if (nni_list_empty(&wm->frames)) {
+
+ if ((frame = nni_list_first(&ws->rxq)) == NULL) {
+ return;
+ }
+
+ // Discard 0 length frames -- in stream mode they are not used.
+ if (frame->len == 0) {
+ nni_list_remove(&ws->rxq, frame);
+ ws_frame_fini(frame);
+ continue;
+ }
+
+ // We are completing this aio one way or the other.
+ nni_aio_list_remove(aio);
+ nni_aio_get_iov(aio, &niov, &iov);
+
+ while ((frame != NULL) && (niov != 0)) {
+ size_t n;
+
+ if ((n = frame->len) > iov->iov_len) {
+ // This eats the entire iov.
+ n = iov->iov_len;
+ }
+ iov->iov_buf = ((uint8_t *) iov->iov_buf) + n;
+ iov->iov_len -= n;
+ if (iov->iov_len == 0) {
+ iov++;
+ niov--;
+ }
+
+ if (frame->len == n) {
+ nni_list_remove(&ws->rxq, frame);
+ ws_frame_fini(frame);
+ frame = nni_list_first(&ws->rxq);
+ } else {
+ frame->len -= n;
+ frame->buf += n;
+ }
+
+ nni_aio_bump_count(aio, n);
+ }
+
+ nni_aio_finish(aio, 0, nni_aio_count(aio));
+ }
+}
+
+static void
+ws_read_finish_msg(nni_ws *ws)
+{
+ nni_aio * aio;
+ size_t len;
+ ws_frame *frame;
+ nni_msg * msg;
+ int rv;
+ uint8_t * body;
+
+ // If we have no data, no waiter, or have not received the complete
+ // message yet, then there is nothing to do.
+ if (ws->inmsg || nni_list_empty(&ws->rxq) ||
+ ((aio = nni_list_first(&ws->recvq)) == NULL)) {
+ return;
+ }
+
+ // At this point, we have both a complete message in the queue (and
+ // there should not be any frames other than the for the message),
+ // and a waiting reader.
+ len = 0;
+ NNI_LIST_FOREACH (&ws->rxq, frame) {
+ len += frame->len;
+ }
+
+ nni_aio_list_remove(aio);
+
+ if ((rv = nni_msg_alloc(&msg, len)) != 0) {
+ nni_aio_finish_error(aio, rv);
+ ws_close_error(ws, WS_CLOSE_INTERNAL);
+ return;
+ }
+ body = nni_msg_body(msg);
+ while ((frame = nni_list_first(&ws->rxq)) != NULL) {
+ nni_list_remove(&ws->rxq, frame);
+ memcpy(body, frame->buf, frame->len);
+ body += frame->len;
+ ws_frame_fini(frame);
+ }
+
+ nni_aio_set_msg(aio, msg);
+ nni_aio_bump_count(aio, nni_msg_len(msg));
+ nni_aio_finish(aio, 0, nni_msg_len(msg));
+}
+
+static void
+ws_read_finish(nni_ws *ws)
+{
+ if (ws->isstream) {
+ ws_read_finish_str(ws);
+ } else {
+ ws_read_finish_msg(ws);
+ }
+}
+
+static void
+ws_read_frame_cb(nni_ws *ws, ws_frame *frame)
+{
+ switch (frame->op) {
+ case WS_CONT:
+ if (!ws->inmsg) {
ws_close(ws, WS_CLOSE_PROTOCOL_ERR);
return;
}
+ if (frame->final) {
+ ws->inmsg = false;
+ }
ws->rxframe = NULL;
- nni_list_append(&wm->frames, frame);
+ nni_list_append(&ws->rxq, frame);
break;
case WS_BINARY:
- if (wm == NULL) {
- ws_close(ws, WS_CLOSE_GOING_AWAY);
- return;
- }
- if (!nni_list_empty(&wm->frames)) {
+ if (ws->inmsg) {
ws_close(ws, WS_CLOSE_PROTOCOL_ERR);
return;
}
+ if (!frame->final) {
+ ws->inmsg = true;
+ }
ws->rxframe = NULL;
- nni_list_append(&wm->frames, frame);
+ nni_list_append(&ws->rxq, frame);
break;
case WS_TEXT:
// No support for text mode at present.
@@ -880,23 +978,13 @@ ws_read_frame_cb(nni_ws *ws, ws_frame *frame, ws_msg **wmp, nni_aio **aiop)
return;
}
- // If this was the last (final) frame, then complete it. But
- // we have to look at the msg, since we might have got a
- // control frame.
- if (((frame = nni_list_last(&wm->frames)) != NULL) && frame->final) {
- nni_list_remove(&ws->rxmsgs, wm);
- *wmp = wm;
- *aiop = wm->aio;
- nni_aio_list_remove(wm->aio);
- wm->aio = NULL;
- }
+ ws_read_finish(ws);
}
static void
ws_read_cb(void *arg)
{
- nni_ws * ws = arg;
- ws_msg * wm;
+ nni_ws * ws = arg;
nni_aio * aio = ws->rxaio;
ws_frame *frame;
int rv;
@@ -976,6 +1064,21 @@ ws_read_cb(void *arg)
nni_mtx_unlock(&ws->mtx);
return;
}
+ // For message mode, also check to make sure that the overall
+ // length of the message has not exceeded our recvmax.
+ // (Protect against an infinite stream of small messages!)
+ if ((!ws->isstream) && (ws->recvmax > 0)) {
+ size_t totlen = frame->len;
+ ws_frame *fr2;
+ NNI_LIST_FOREACH (&ws->rxq, fr2) {
+ totlen += fr2->len;
+ }
+ if (totlen > ws->recvmax) {
+ ws_close(ws, WS_CLOSE_TOO_BIG);
+ nni_mtx_unlock(&ws->mtx);
+ return;
+ }
+ }
// Check for masking. (We don't actually do the unmask
// here, because we don't have data yet.)
@@ -1023,134 +1126,40 @@ ws_read_cb(void *arg)
// At this point, we have a complete frame.
ws_unmask_frame(frame); // idempotent
- wm = NULL;
- aio = NULL;
- ws_read_frame_cb(ws, frame, &wm, &aio);
+ ws_read_frame_cb(ws, frame);
ws_start_read(ws);
nni_mtx_unlock(&ws->mtx);
-
- // Got a good message, so we have to do the work to send it up.
- if (wm != NULL) {
- size_t len = 0;
- nni_msg *msg;
- uint8_t *body;
- int rv;
-
- NNI_LIST_FOREACH (&wm->frames, frame) {
- len += frame->len;
- }
- if ((rv = nni_msg_alloc(&msg, len)) != 0) {
- nni_aio_finish_error(aio, rv);
- ws_msg_fini(wm);
- nni_ws_close_error(ws, WS_CLOSE_INTERNAL);
- return;
- }
- body = nni_msg_body(msg);
- NNI_LIST_FOREACH (&wm->frames, frame) {
- memcpy(body, frame->buf, frame->len);
- body += frame->len;
- }
- nni_aio_set_msg(aio, msg);
- nni_aio_finish_synch(aio, 0, nni_msg_len(msg));
- ws_msg_fini(wm);
- }
}
static void
ws_read_cancel(nni_aio *aio, void *arg, int rv)
{
nni_ws *ws = arg;
- ws_msg *wm;
nni_mtx_lock(&ws->mtx);
- if (!nni_aio_list_active(aio)) {
- nni_mtx_unlock(&ws->mtx);
- return;
- }
- wm = nni_aio_get_prov_extra(aio, 0);
- if (wm == nni_list_first(&ws->rxmsgs)) {
- // Cancellation will percolate back up.
- nni_aio_abort(ws->rxaio, rv);
- } else if (nni_list_active(&ws->rxmsgs, wm)) {
- nni_list_remove(&ws->rxmsgs, wm);
- ws_msg_fini(wm);
+ if (nni_aio_list_active(aio)) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
}
nni_mtx_unlock(&ws->mtx);
}
-void
-nni_ws_recv_msg(nni_ws *ws, nni_aio *aio)
-{
- ws_msg *wm;
- int rv;
-
- if (nni_aio_begin(aio) != 0) {
- return;
- }
- if ((rv = ws_msg_init_rx(&wm, ws, aio)) != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
- nni_mtx_lock(&ws->mtx);
- if ((rv = nni_aio_schedule(aio, ws_read_cancel, ws)) != 0) {
- nni_mtx_unlock(&ws->mtx);
- ws_msg_fini(wm);
- nni_aio_finish_error(aio, rv);
- return;
- }
- nni_aio_set_prov_extra(aio, 0, wm);
- nni_list_append(&ws->recvq, aio);
- nni_list_append(&ws->rxmsgs, wm);
- ws_start_read(ws);
-
- nni_mtx_unlock(&ws->mtx);
-}
-
-void
-nni_ws_close_error(nni_ws *ws, uint16_t code)
+static void
+ws_close_error(nni_ws *ws, uint16_t code)
{
nni_mtx_lock(&ws->mtx);
ws_close(ws, code);
nni_mtx_unlock(&ws->mtx);
}
-void
-nni_ws_close(nni_ws *ws)
-{
- nni_ws_close_error(ws, WS_CLOSE_NORMAL_CLOSE);
-}
-
-const char *
-nni_ws_request_headers(nni_ws *ws)
-{
- nni_mtx_lock(&ws->mtx);
- if (ws->reqhdrs == NULL) {
- ws->reqhdrs = nni_http_req_headers(ws->req);
- }
- nni_mtx_unlock(&ws->mtx);
- return (ws->reqhdrs);
-}
-
-const char *
-nni_ws_response_headers(nni_ws *ws)
-{
- nni_mtx_lock(&ws->mtx);
- if (ws->reshdrs == NULL) {
- ws->reshdrs = nni_http_res_headers(ws->res);
- }
- nni_mtx_unlock(&ws->mtx);
- return (ws->reshdrs);
-}
-
static void
ws_fini(void *arg)
{
- nni_ws *ws = arg;
- ws_msg *wm;
+ nni_ws * ws = arg;
+ ws_frame *frame;
+ nng_aio * aio;
- nni_ws_close(ws);
+ ws_close_error(ws, WS_CLOSE_NORMAL_CLOSE);
// Give a chance for the close frame to drain.
if (ws->closeaio) {
@@ -1175,25 +1184,29 @@ ws_fini(void *arg)
}
nni_mtx_lock(&ws->mtx);
- while ((wm = nni_list_first(&ws->rxmsgs)) != NULL) {
- nni_list_remove(&ws->rxmsgs, wm);
- if (wm->aio) {
- nni_aio_finish_error(wm->aio, NNG_ECLOSED);
- }
- ws_msg_fini(wm);
+ while ((frame = nni_list_first(&ws->rxq)) != NULL) {
+ nni_list_remove(&ws->rxq, frame);
+ ws_frame_fini(frame);
}
- while ((wm = nni_list_first(&ws->txmsgs)) != NULL) {
- nni_list_remove(&ws->txmsgs, wm);
- if (wm->aio) {
- nni_aio_finish_error(wm->aio, NNG_ECLOSED);
- }
- ws_msg_fini(wm);
+ while ((frame = nni_list_first(&ws->txq)) != NULL) {
+ nni_list_remove(&ws->txq, frame);
+ ws_frame_fini(frame);
}
- if (ws->rxframe) {
+ if (ws->rxframe != NULL) {
ws_frame_fini(ws->rxframe);
}
+ if (ws->txframe != NULL) {
+ ws_frame_fini(ws->txframe);
+ }
+
+ while (((aio = nni_list_first(&ws->recvq)) != NULL) ||
+ ((aio = nni_list_first(&ws->sendq)) != NULL)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+
nni_mtx_unlock(&ws->mtx);
if (ws->http) {
@@ -1217,8 +1230,8 @@ ws_fini(void *arg)
NNI_FREE_STRUCT(ws);
}
-void
-nni_ws_fini(nni_ws *ws)
+static void
+ws_reap(nni_ws *ws)
{
nni_reap(&ws->reap, ws_fini, ws);
}
@@ -1232,8 +1245,8 @@ ws_http_cb_listener(nni_ws *ws, nni_aio *aio)
nni_mtx_lock(&l->mtx);
nni_list_remove(&l->reply, ws);
if (nni_aio_result(aio) != 0) {
- nni_ws_fini(ws);
nni_mtx_unlock(&l->mtx);
+ ws_reap(ws);
return;
}
ws->ready = true;
@@ -1320,14 +1333,14 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio)
(!ws_contains_word(ptr, "upgrade")) ||
((ptr = GETH("Upgrade")) == NULL) ||
(strcmp(ptr, "websocket") != 0)) {
- nni_ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR);
+ ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR);
rv = NNG_EPROTO;
goto err;
}
if (d->proto != NULL) {
if (((ptr = GETH("Sec-WebSocket-Protocol")) == NULL) ||
(!ws_contains_word(d->proto, ptr))) {
- nni_ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR);
+ ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR);
rv = NNG_EPROTO;
goto err;
}
@@ -1358,7 +1371,7 @@ err:
}
nni_mtx_unlock(&d->mtx);
- nni_ws_fini(ws);
+ ws_reap(ws);
}
static void
@@ -1384,8 +1397,8 @@ ws_init(nni_ws **wsp)
return (NNG_ENOMEM);
}
nni_mtx_init(&ws->mtx);
- NNI_LIST_INIT(&ws->rxmsgs, ws_msg, node);
- NNI_LIST_INIT(&ws->txmsgs, ws_msg, node);
+ NNI_LIST_INIT(&ws->rxq, ws_frame, node);
+ NNI_LIST_INIT(&ws->txq, ws_frame, node);
nni_aio_list_init(&ws->sendq);
nni_aio_list_init(&ws->recvq);
@@ -1401,17 +1414,25 @@ ws_init(nni_ws **wsp)
nni_aio_set_timeout(ws->closeaio, 100);
nni_aio_set_timeout(ws->httpaio, 2000);
+ ws->ops.s_close = ws_str_close;
+ ws->ops.s_free = ws_str_free;
+ ws->ops.s_send = ws_str_send;
+ ws->ops.s_recv = ws_str_recv;
+ ws->ops.s_getx = ws_str_getx;
+ ws->ops.s_setx = ws_str_setx;
+
ws->fragsize = 1 << 20; // we won't send a frame larger than this
*wsp = ws;
return (0);
}
-void
-nni_ws_listener_fini(nni_ws_listener *l)
+static void
+ws_listener_free(void *arg)
{
- ws_header *hdr;
+ nni_ws_listener *l = arg;
+ ws_header * hdr;
- nni_ws_listener_close(l);
+ ws_listener_close(l);
nni_mtx_lock(&l->mtx);
while (!nni_list_empty(&l->reply)) {
@@ -1437,7 +1458,7 @@ nni_ws_listener_fini(nni_ws_listener *l)
NNI_FREE_STRUCT(hdr);
}
if (l->url) {
- nni_url_free(l->url);
+ nng_url_free(l->url);
}
NNI_FREE_STRUCT(l);
}
@@ -1456,6 +1477,7 @@ ws_handler(nni_aio *aio)
uint16_t status;
int rv;
char key[29];
+ ws_header * hdr;
req = nni_aio_get_input(aio, 0);
h = nni_aio_get_input(aio, 1);
@@ -1542,6 +1564,20 @@ ws_handler(nni_aio *aio)
goto err;
}
+ // Set any user supplied headers. This is better than using a hook
+ // for most things, because it is loads easier.
+ NNI_LIST_FOREACH (&l->headers, hdr) {
+ if (SETH(hdr->name, hdr->value) != 0) {
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ nni_http_res_free(res);
+ goto err;
+ }
+ }
+
+ // The hook function gives us the ability to intercept the HTTP
+ // response altogether. Its best not to do this unless you really
+ // need to, because it's much more complex. But if you want to set
+ // up an HTTP Authorization handler this might be the only choice.
if (l->hookfn != NULL) {
rv = l->hookfn(l->hookarg, req, res);
if (rv != 0) {
@@ -1583,8 +1619,9 @@ ws_handler(nni_aio *aio)
ws->res = res;
ws->server = true;
ws->maxframe = l->maxframe;
-
- // XXX: Inherit fragmentation? (Frag is limited for now).
+ ws->fragsize = l->fragsize;
+ ws->recvmax = l->recvmax;
+ ws->isstream = l->isstream;
nni_list_append(&l->reply, ws);
nni_aio_set_data(ws->httpaio, 0, l);
@@ -1603,71 +1640,6 @@ err:
}
}
-int
-nni_ws_listener_init(nni_ws_listener **wslp, nni_url *url)
-{
- nni_ws_listener *l;
- int rv;
- char * host;
-
- if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
- return (NNG_ENOMEM);
- }
- nni_mtx_init(&l->mtx);
- nni_cv_init(&l->cv, &l->mtx);
- nni_aio_list_init(&l->aios);
-
- NNI_LIST_INIT(&l->pend, nni_ws, node);
- NNI_LIST_INIT(&l->reply, nni_ws, node);
-
- // make a private copy of the url structure.
- if ((rv = nni_url_clone(&l->url, url)) != 0) {
- nni_ws_listener_fini(l);
- return (rv);
- }
-
- host = l->url->u_hostname;
- if (strlen(host) == 0) {
- host = NULL;
- }
- rv = nni_http_handler_init(&l->handler, url->u_path, ws_handler);
- if (rv != 0) {
- nni_ws_listener_fini(l);
- return (rv);
- }
-
- if (((rv = nni_http_handler_set_host(l->handler, host)) != 0) ||
- ((rv = nni_http_handler_set_data(l->handler, l, 0)) != 0) ||
- ((rv = nni_http_server_init(&l->server, url)) != 0)) {
- nni_ws_listener_fini(l);
- return (rv);
- }
-
- l->maxframe = 0;
- *wslp = l;
- return (0);
-}
-
-int
-nni_ws_listener_proto(nni_ws_listener *l, const char *proto)
-{
- int rv = 0;
- char *ns;
- nni_mtx_lock(&l->mtx);
- if (l->started) {
- rv = NNG_EBUSY;
- } else if ((ns = nni_strdup(proto)) == NULL) {
- rv = NNG_ENOMEM;
- } else {
- if (l->proto != NULL) {
- nni_strfree(l->proto);
- }
- l->proto = ns;
- }
- nni_mtx_unlock(&l->mtx);
- return (rv);
-}
-
static void
ws_accept_cancel(nni_aio *aio, void *arg, int rv)
{
@@ -1681,11 +1653,12 @@ ws_accept_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ws_listener_accept(nni_ws_listener *l, nni_aio *aio)
+static void
+ws_listener_accept(void *arg, nni_aio *aio)
{
- nni_ws *ws;
- int rv;
+ nni_ws_listener *l = arg;
+ nni_ws * ws;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
@@ -1717,10 +1690,11 @@ nni_ws_listener_accept(nni_ws_listener *l, nni_aio *aio)
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ws_listener_close(nni_ws_listener *l)
+static void
+ws_listener_close(void *arg)
{
- nni_ws *ws;
+ nni_ws_listener *l = arg;
+ nni_ws * ws;
nni_mtx_lock(&l->mtx);
if (l->closed) {
nni_mtx_unlock(&l->mtx);
@@ -1733,18 +1707,30 @@ nni_ws_listener_close(nni_ws_listener *l)
l->started = false;
}
NNI_LIST_FOREACH (&l->pend, ws) {
- nni_ws_close_error(ws, WS_CLOSE_GOING_AWAY);
+ ws_close_error(ws, WS_CLOSE_GOING_AWAY);
}
NNI_LIST_FOREACH (&l->reply, ws) {
- nni_ws_close_error(ws, WS_CLOSE_GOING_AWAY);
+ ws_close_error(ws, WS_CLOSE_GOING_AWAY);
}
nni_mtx_unlock(&l->mtx);
}
-int
-nni_ws_listener_listen(nni_ws_listener *l)
+// XXX: Consider replacing this with an option.
+void
+nni_ws_listener_hook(
+ nni_ws_listener *l, nni_ws_listen_hook hookfn, void *hookarg)
{
- int rv;
+ nni_mtx_lock(&l->mtx);
+ l->hookfn = hookfn;
+ l->hookarg = hookarg;
+ nni_mtx_unlock(&l->mtx);
+}
+
+static int
+ws_listener_listen(void *arg)
+{
+ nni_ws_listener *l = arg;
+ int rv;
nni_mtx_lock(&l->mtx);
if (l->closed) {
@@ -1777,42 +1763,290 @@ nni_ws_listener_listen(nni_ws_listener *l)
return (0);
}
-void
-nni_ws_listener_hook(
- nni_ws_listener *l, nni_ws_listen_hook hookfn, void *hookarg)
+static int
+ws_listener_set_size(
+ nni_ws_listener *l, size_t *valp, const void *buf, size_t sz, nni_type t)
{
- nni_mtx_lock(&l->mtx);
- l->hookfn = hookfn;
- l->hookarg = hookarg;
- nni_mtx_unlock(&l->mtx);
+ size_t val;
+ int rv;
+
+ // Max size is limited to 4 GB, but you really never want to have
+ // to have a larger value. If you think you need that, you're doing it
+ // wrong. You *can* set the size to 0 for unlimited.
+ if ((rv = nni_copyin_size(&val, buf, sz, 0, NNI_MAXSZ, t)) == 0) {
+ nni_mtx_lock(&l->mtx);
+ *valp = val;
+ nni_mtx_unlock(&l->mtx);
+ }
+ return (rv);
}
-int
-nni_ws_listener_set_tls(nni_ws_listener *l, nng_tls_config *tls)
+static int
+ws_listener_get_size(
+ nni_ws_listener *l, size_t *valp, void *buf, size_t *szp, nni_type t)
{
- int rv;
+ size_t val;
nni_mtx_lock(&l->mtx);
- rv = nni_http_server_set_tls(l->server, tls);
+ val = *valp;
nni_mtx_unlock(&l->mtx);
+ return (nni_copyout_size(val, buf, szp, t));
+}
+
+static int
+ws_listener_set_maxframe(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_set_size(l, &l->maxframe, buf, sz, t));
+}
+
+static int
+ws_listener_get_maxframe(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_get_size(l, &l->maxframe, buf, szp, t));
+}
+
+static int
+ws_listener_set_fragsize(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_set_size(l, &l->fragsize, buf, sz, t));
+}
+
+static int
+ws_listener_get_fragsize(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_get_size(l, &l->fragsize, buf, szp, t));
+}
+
+static int
+ws_listener_set_recvmax(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_set_size(l, &l->recvmax, buf, sz, t));
+}
+
+static int
+ws_listener_get_recvmax(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ return (ws_listener_get_size(l, &l->recvmax, buf, szp, t));
+}
+
+static int
+ws_listener_set_res_headers(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ int rv;
+
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->mtx);
+ rv = ws_set_headers(&l->headers, buf);
+ nni_mtx_unlock(&l->mtx);
+ }
return (rv);
}
-int
-nni_ws_listener_get_tls(nni_ws_listener *l, nng_tls_config **tlsp)
+static int
+ws_listener_set_proto(void *arg, const void *buf, size_t sz, nni_type t)
{
- int rv;
+ nni_ws_listener *l = arg;
+ int rv;
+
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ char *ns;
+ if ((ns = nni_strdup(buf)) == NULL) {
+ rv = NNG_ENOMEM;
+ } else {
+ nni_mtx_lock(&l->mtx);
+ if (l->proto != NULL) {
+ nni_strfree(l->proto);
+ }
+ l->proto = ns;
+ nni_mtx_unlock(&l->mtx);
+ }
+ }
+ return (rv);
+}
+
+static int
+ws_listener_get_proto(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ int rv;
nni_mtx_lock(&l->mtx);
- rv = nni_http_server_get_tls(l->server, tlsp);
+ rv = nni_copyout_str(l->proto != NULL ? l->proto : "", buf, szp, t);
nni_mtx_unlock(&l->mtx);
return (rv);
}
-void
-nni_ws_listener_set_maxframe(nni_ws_listener *l, size_t maxframe)
+static int
+ws_listener_set_msgmode(void *arg, const void *buf, size_t sz, nni_type t)
{
+ nni_ws_listener *l = arg;
+ int rv;
+ bool b;
+
+ if ((rv = nni_copyin_bool(&b, buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->mtx);
+ l->isstream = !b;
+ nni_mtx_unlock(&l->mtx);
+ }
+ return (rv);
+}
+
+static int
+ws_listener_get_url(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ int rv;
+
nni_mtx_lock(&l->mtx);
- l->maxframe = maxframe;
+ rv = nni_copyout_str(l->url->u_rawurl, buf, szp, t);
nni_mtx_unlock(&l->mtx);
+ return (rv);
+}
+
+static const nni_option ws_listener_options[] = {
+ {
+ .o_name = NNI_OPT_WS_MSGMODE,
+ .o_set = ws_listener_set_msgmode,
+ },
+ {
+ .o_name = NNG_OPT_WS_RECVMAXFRAME,
+ .o_set = ws_listener_set_maxframe,
+ .o_get = ws_listener_get_maxframe,
+ },
+ {
+ .o_name = NNG_OPT_WS_SENDMAXFRAME,
+ .o_set = ws_listener_set_fragsize,
+ .o_get = ws_listener_get_fragsize,
+ },
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_set = ws_listener_set_recvmax,
+ .o_get = ws_listener_get_recvmax,
+ },
+ {
+ .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
+ .o_set = ws_listener_set_res_headers,
+ // XXX: Get not implemented yet; likely of marginal value.
+ },
+ {
+ .o_name = NNG_OPT_WS_PROTOCOL,
+ .o_set = ws_listener_set_proto,
+ .o_get = ws_listener_get_proto,
+ },
+ {
+ .o_name = NNG_OPT_URL,
+ .o_get = ws_listener_get_url,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+ws_listener_set_header(nni_ws_listener *l, const char *name, const void *buf,
+ size_t sz, nni_type t)
+{
+ int rv;
+ name += strlen(NNG_OPT_WS_RESPONSE_HEADER);
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->mtx);
+ rv = ws_set_header(&l->headers, name, buf);
+ nni_mtx_unlock(&l->mtx);
+ }
+ return (rv);
+}
+
+static int
+ws_listener_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ int rv;
+
+ rv = nni_setopt(ws_listener_options, name, l, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_http_server_setx(l->server, name, buf, sz, t);
+ }
+
+ if (rv == NNG_ENOTSUP) {
+ if (startswith(name, NNG_OPT_WS_RESPONSE_HEADER)) {
+ rv = ws_listener_set_header(l, name, buf, sz, t);
+ }
+ }
+ return (rv);
+}
+
+static int
+ws_listener_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_listener *l = arg;
+ int rv;
+
+ rv = nni_getopt(ws_listener_options, name, l, buf, szp, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_http_server_getx(l->server, name, buf, szp, t);
+ }
+ return (rv);
+}
+
+int
+nni_ws_listener_alloc(nng_stream_listener **wslp, const nng_url *url)
+{
+ nni_ws_listener *l;
+ int rv;
+ char * host;
+
+ if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ nni_mtx_init(&l->mtx);
+ nni_cv_init(&l->cv, &l->mtx);
+ nni_aio_list_init(&l->aios);
+
+ NNI_LIST_INIT(&l->pend, nni_ws, node);
+ NNI_LIST_INIT(&l->reply, nni_ws, node);
+
+ // make a private copy of the url structure.
+ if ((rv = nng_url_clone(&l->url, url)) != 0) {
+ ws_listener_free(l);
+ return (rv);
+ }
+
+ host = l->url->u_hostname;
+ if (strlen(host) == 0) {
+ host = NULL;
+ }
+ rv = nni_http_handler_init(&l->handler, url->u_path, ws_handler);
+ if (rv != 0) {
+ ws_listener_free(l);
+ return (rv);
+ }
+
+ if (((rv = nni_http_handler_set_host(l->handler, host)) != 0) ||
+ ((rv = nni_http_handler_set_data(l->handler, l, 0)) != 0) ||
+ ((rv = nni_http_server_init(&l->server, url)) != 0)) {
+ ws_listener_free(l);
+ return (rv);
+ }
+
+ l->fragsize = WS_DEF_MAXTXFRAME;
+ l->maxframe = WS_DEF_MAXRXFRAME;
+ l->recvmax = WS_DEF_RECVMAX;
+ l->isstream = false;
+ l->ops.sl_free = ws_listener_free;
+ l->ops.sl_close = ws_listener_close;
+ l->ops.sl_accept = ws_listener_accept;
+ l->ops.sl_listen = ws_listener_listen;
+ l->ops.sl_setx = ws_listener_setx;
+ l->ops.sl_getx = ws_listener_getx;
+ *wslp = (void *) l;
+ return (0);
}
void
@@ -1846,7 +2080,7 @@ ws_conn_cb(void *arg)
nni_cv_wake(&d->cv);
}
nni_mtx_unlock(&d->mtx);
- nni_ws_fini(ws);
+ ws_reap(ws);
} else {
nni_mtx_unlock(&d->mtx);
}
@@ -1861,7 +2095,7 @@ ws_conn_cb(void *arg)
// This request was canceled for some reason.
nni_http_conn_fini(http);
nni_mtx_unlock(&ws->mtx);
- nni_ws_fini(ws);
+ ws_reap(ws);
return;
}
@@ -1908,13 +2142,14 @@ err:
if (req != NULL) {
nni_http_req_free(req);
}
- nni_ws_fini(ws);
+ ws_reap(ws);
}
-void
-nni_ws_dialer_fini(nni_ws_dialer *d)
+static void
+ws_dialer_free(void *arg)
{
- ws_header *hdr;
+ nni_ws_dialer *d = arg;
+ ws_header * hdr;
nni_mtx_lock(&d->mtx);
while (!nni_list_empty(&d->wspend)) {
@@ -1933,65 +2168,18 @@ nni_ws_dialer_fini(nni_ws_dialer *d)
nni_http_client_fini(d->client);
}
if (d->url) {
- nni_url_free(d->url);
+ nng_url_free(d->url);
}
nni_cv_fini(&d->cv);
nni_mtx_fini(&d->mtx);
NNI_FREE_STRUCT(d);
}
-int
-nni_ws_dialer_init(nni_ws_dialer **dp, nni_url *url)
-{
- nni_ws_dialer *d;
- int rv;
-
- if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
- return (NNG_ENOMEM);
- }
- NNI_LIST_INIT(&d->headers, ws_header, node);
- NNI_LIST_INIT(&d->wspend, nni_ws, node);
- nni_mtx_init(&d->mtx);
- nni_cv_init(&d->cv, &d->mtx);
-
- if ((rv = nni_url_clone(&d->url, url)) != 0) {
- nni_ws_dialer_fini(d);
- return (rv);
- }
-
- if ((rv = nni_http_client_init(&d->client, url)) != 0) {
- nni_ws_dialer_fini(d);
- return (rv);
- }
- d->maxframe = 0;
- *dp = d;
- return (0);
-}
-
-int
-nni_ws_dialer_set_tls(nni_ws_dialer *d, nng_tls_config *tls)
-{
- int rv;
- nni_mtx_lock(&d->mtx);
- rv = nni_http_client_set_tls(d->client, tls);
- nni_mtx_unlock(&d->mtx);
- return (rv);
-}
-
-int
-nni_ws_dialer_get_tls(nni_ws_dialer *d, nng_tls_config **tlsp)
-{
- int rv;
- nni_mtx_lock(&d->mtx);
- rv = nni_http_client_get_tls(d->client, tlsp);
- nni_mtx_unlock(&d->mtx);
- return (rv);
-}
-
-void
-nni_ws_dialer_close(nni_ws_dialer *d)
+static void
+ws_dialer_close(void *arg)
{
- nni_ws *ws;
+ nni_ws_dialer *d = arg;
+ nni_ws * ws;
nni_mtx_lock(&d->mtx);
if (d->closed) {
nni_mtx_unlock(&d->mtx);
@@ -2005,24 +2193,6 @@ nni_ws_dialer_close(nni_ws_dialer *d)
nni_mtx_unlock(&d->mtx);
}
-int
-nni_ws_dialer_proto(nni_ws_dialer *d, const char *proto)
-{
- int rv = 0;
- char *ns;
- nni_mtx_lock(&d->mtx);
- if ((ns = nni_strdup(proto)) == NULL) {
- rv = NNG_ENOMEM;
- } else {
- if (d->proto != NULL) {
- nni_strfree(d->proto);
- }
- d->proto = ns;
- }
- nni_mtx_unlock(&d->mtx);
- return (rv);
-}
-
static void
ws_dial_cancel(nni_aio *aio, void *arg, int rv)
{
@@ -2038,11 +2208,12 @@ ws_dial_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&ws->mtx);
}
-void
-nni_ws_dialer_dial(nni_ws_dialer *d, nni_aio *aio)
+static void
+ws_dialer_dial(void *arg, nni_aio *aio)
{
- nni_ws *ws;
- int rv;
+ nni_ws_dialer *d = arg;
+ nni_ws * ws;
+ int rv;
if (nni_aio_begin(aio) != 0) {
return;
@@ -2055,72 +2226,275 @@ nni_ws_dialer_dial(nni_ws_dialer *d, nni_aio *aio)
if (d->closed) {
nni_mtx_unlock(&d->mtx);
nni_aio_finish_error(aio, NNG_ECLOSED);
- ws_fini(ws);
+ ws_reap(ws);
return;
}
if ((rv = nni_aio_schedule(aio, ws_dial_cancel, ws)) != 0) {
nni_mtx_unlock(&d->mtx);
nni_aio_finish_error(aio, rv);
- ws_fini(ws);
+ ws_reap(ws);
return;
}
ws->dialer = d;
ws->useraio = aio;
ws->server = false;
ws->maxframe = d->maxframe;
+ ws->isstream = d->isstream;
nni_list_append(&d->wspend, ws);
nni_http_client_connect(d->client, ws->connaio);
nni_mtx_unlock(&d->mtx);
}
static int
-ws_set_header(nni_list *l, const char *n, const char *v)
+ws_dialer_set_msgmode(void *arg, const void *buf, size_t sz, nni_type t)
{
- ws_header *hdr;
- char * nv;
+ nni_ws_dialer *d = arg;
+ int rv;
+ bool b;
- if ((nv = nni_strdup(v)) == NULL) {
- return (NNG_ENOMEM);
+ if ((rv = nni_copyin_bool(&b, buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->mtx);
+ d->isstream = !b;
+ nni_mtx_unlock(&d->mtx);
}
+ return (rv);
+}
- NNI_LIST_FOREACH (l, hdr) {
- if (nni_strcasecmp(hdr->name, n) == 0) {
- nni_strfree(hdr->value);
- hdr->value = nv;
- return (0);
- }
- }
+static int
+ws_dialer_set_size(
+ nni_ws_dialer *d, size_t *valp, const void *buf, size_t sz, nni_type t)
+{
+ size_t val;
+ int rv;
- if ((hdr = NNI_ALLOC_STRUCT(hdr)) == NULL) {
- nni_strfree(nv);
- return (NNG_ENOMEM);
- }
- if ((hdr->name = nni_strdup(n)) == NULL) {
- nni_strfree(nv);
- NNI_FREE_STRUCT(hdr);
- return (NNG_ENOMEM);
+ // Max size is limited to 4 GB, but you really never want to have
+ // to have a larger value. If you think you need that, you're doing it
+ // wrong. You *can* set the size to 0 for unlimited.
+ if ((rv = nni_copyin_size(&val, buf, sz, 0, NNI_MAXSZ, t)) == 0) {
+ nni_mtx_lock(&d->mtx);
+ *valp = val;
+ nni_mtx_unlock(&d->mtx);
}
- hdr->value = nv;
- nni_list_append(l, hdr);
- return (0);
+ return (rv);
}
-int
-nni_ws_dialer_header(nni_ws_dialer *d, const char *n, const char *v)
+static int
+ws_dialer_get_size(
+ nni_ws_dialer *d, size_t *valp, void *buf, size_t *szp, nni_type t)
{
- int rv;
+ size_t val;
nni_mtx_lock(&d->mtx);
- rv = ws_set_header(&d->headers, n, v);
+ val = *valp;
nni_mtx_unlock(&d->mtx);
+ return (nni_copyout_size(val, buf, szp, t));
+}
+
+static int
+ws_dialer_set_maxframe(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_set_size(d, &d->maxframe, buf, sz, t));
+}
+
+static int
+ws_dialer_get_maxframe(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_get_size(d, &d->maxframe, buf, szp, t));
+}
+
+static int
+ws_dialer_set_fragsize(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_set_size(d, &d->fragsize, buf, sz, t));
+}
+
+static int
+ws_dialer_get_fragsize(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_get_size(d, &d->fragsize, buf, szp, t));
+}
+
+static int
+ws_dialer_set_recvmax(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_set_size(d, &d->recvmax, buf, sz, t));
+}
+
+static int
+ws_dialer_get_recvmax(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ return (ws_dialer_get_size(d, &d->recvmax, buf, szp, t));
+}
+
+static int
+ws_dialer_set_req_headers(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ int rv;
+
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->mtx);
+ rv = ws_set_headers(&d->headers, buf);
+ nni_mtx_unlock(&d->mtx);
+ }
return (rv);
}
-void
-nni_ws_dialer_set_maxframe(nni_ws_dialer *d, size_t maxframe)
+static int
+ws_dialer_set_proto(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ int rv;
+
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ char *ns;
+ if ((ns = nni_strdup(buf)) == NULL) {
+ rv = NNG_ENOMEM;
+ } else {
+ nni_mtx_lock(&d->mtx);
+ if (d->proto != NULL) {
+ nni_strfree(d->proto);
+ }
+ d->proto = ns;
+ nni_mtx_unlock(&d->mtx);
+ }
+ }
+ return (rv);
+}
+
+static int
+ws_dialer_get_proto(void *arg, void *buf, size_t *szp, nni_type t)
{
+ nni_ws_dialer *d = arg;
+ int rv;
nni_mtx_lock(&d->mtx);
- d->maxframe = maxframe;
+ rv = nni_copyout_str(d->proto != NULL ? d->proto : "", buf, szp, t);
nni_mtx_unlock(&d->mtx);
+ return (rv);
+}
+
+static const nni_option ws_dialer_options[] = {
+ {
+ .o_name = NNI_OPT_WS_MSGMODE,
+ .o_set = ws_dialer_set_msgmode,
+ },
+ {
+ .o_name = NNG_OPT_WS_RECVMAXFRAME,
+ .o_set = ws_dialer_set_maxframe,
+ .o_get = ws_dialer_get_maxframe,
+ },
+ {
+ .o_name = NNG_OPT_WS_SENDMAXFRAME,
+ .o_set = ws_dialer_set_fragsize,
+ .o_get = ws_dialer_get_fragsize,
+ },
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_set = ws_dialer_set_recvmax,
+ .o_get = ws_dialer_get_recvmax,
+ },
+ {
+ .o_name = NNG_OPT_WS_REQUEST_HEADERS,
+ .o_set = ws_dialer_set_req_headers,
+ // XXX: Get not implemented yet; likely of marginal value.
+ },
+ {
+ .o_name = NNG_OPT_WS_PROTOCOL,
+ .o_set = ws_dialer_set_proto,
+ .o_get = ws_dialer_get_proto,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+ws_dialer_set_header(
+ nni_ws_dialer *d, const char *name, const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ name += strlen(NNG_OPT_WS_REQUEST_HEADER);
+ if ((rv = ws_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->mtx);
+ rv = ws_set_header(&d->headers, name, buf);
+ nni_mtx_unlock(&d->mtx);
+ }
+ return (rv);
+}
+
+static int
+ws_dialer_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ int rv;
+
+ rv = nni_setopt(ws_dialer_options, name, d, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_http_client_setx(d->client, name, buf, sz, t);
+ }
+
+ if (rv == NNG_ENOTSUP) {
+ if (startswith(name, NNG_OPT_WS_REQUEST_HEADER)) {
+ rv = ws_dialer_set_header(d, name, buf, sz, t);
+ }
+ }
+ return (rv);
+}
+
+static int
+ws_dialer_getx(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws_dialer *d = arg;
+ int rv;
+
+ rv = nni_getopt(ws_dialer_options, name, d, buf, szp, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_http_client_getx(d->client, name, buf, szp, t);
+ }
+ return (rv);
+}
+
+int
+nni_ws_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
+{
+ nni_ws_dialer *d;
+ int rv;
+
+ if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ NNI_LIST_INIT(&d->headers, ws_header, node);
+ NNI_LIST_INIT(&d->wspend, nni_ws, node);
+ nni_mtx_init(&d->mtx);
+ nni_cv_init(&d->cv, &d->mtx);
+
+ if ((rv = nng_url_clone(&d->url, url)) != 0) {
+ ws_dialer_free(d);
+ return (rv);
+ }
+
+ if ((rv = nni_http_client_init(&d->client, url)) != 0) {
+ ws_dialer_free(d);
+ return (rv);
+ }
+ d->isstream = true;
+ d->recvmax = WS_DEF_RECVMAX;
+ d->maxframe = WS_DEF_MAXRXFRAME;
+ d->fragsize = WS_DEF_MAXTXFRAME;
+
+ d->ops.sd_free = ws_dialer_free;
+ d->ops.sd_close = ws_dialer_close;
+ d->ops.sd_dial = ws_dialer_dial;
+ d->ops.sd_setx = ws_dialer_setx;
+ d->ops.sd_getx = ws_dialer_getx;
+ *dp = (void *) d;
+ return (0);
}
// Dialer does not get a hook chance, as it can examine the request
@@ -2130,3 +2504,293 @@ nni_ws_dialer_set_maxframe(nni_ws_dialer *d, size_t maxframe)
// The implementation will send periodic PINGs, and respond with
// PONGs.
+
+static void
+ws_str_free(void *arg)
+{
+ nni_ws *ws = arg;
+ nni_reap(&ws->reap, ws_fini, ws);
+}
+
+static void
+ws_str_close(void *arg)
+{
+ nni_ws *ws = arg;
+ ws_close_error(ws, WS_CLOSE_NORMAL_CLOSE);
+}
+
+static void
+ws_str_send(void *arg, nni_aio *aio)
+{
+ nni_ws * ws = arg;
+ int rv;
+ ws_frame *frame;
+
+ if (nni_aio_begin(aio) != 0) {
+ return;
+ }
+
+ if (!ws->isstream) {
+ nni_msg *msg;
+ unsigned niov;
+ nni_iov iov[2];
+ if ((msg = nni_aio_get_msg(aio)) == NULL) {
+ nni_aio_finish_error(aio, NNG_EINVAL);
+ return;
+ }
+ niov = 0;
+ if (nng_msg_header_len(msg) > 0) {
+ iov[niov].iov_len = nni_msg_header_len(msg);
+ iov[niov].iov_buf = nni_msg_header(msg);
+ niov++;
+ }
+ iov[niov].iov_len = nni_msg_len(msg);
+ iov[niov].iov_buf = nni_msg_body(msg);
+ niov++;
+
+ // Scribble into the iov for now.
+ nni_aio_set_iov(aio, niov, iov);
+ }
+
+ if ((frame = NNI_ALLOC_STRUCT(frame)) == NULL) {
+ nni_aio_finish_error(aio, NNG_ENOMEM);
+ return;
+ }
+ frame->aio = aio;
+ if ((rv = ws_frame_prep_tx(ws, frame)) != 0) {
+ nni_aio_finish_error(aio, rv);
+ ws_frame_fini(frame);
+ return;
+ }
+
+ nni_mtx_lock(&ws->mtx);
+
+ if (ws->closed) {
+ nni_mtx_unlock(&ws->mtx);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ ws_frame_fini(frame);
+ return;
+ }
+ if ((rv = nni_aio_schedule(aio, ws_write_cancel, ws)) != 0) {
+ nni_mtx_unlock(&ws->mtx);
+ nni_aio_finish_error(aio, rv);
+ ws_frame_fini(frame);
+ return;
+ }
+ nni_aio_set_prov_extra(aio, 0, frame);
+ nni_list_append(&ws->sendq, aio);
+ nni_list_append(&ws->txq, frame);
+ ws_start_write(ws);
+ nni_mtx_unlock(&ws->mtx);
+}
+
+static void
+ws_str_recv(void *arg, nng_aio *aio)
+{
+ nni_ws *ws = arg;
+ int rv;
+
+ if (nni_aio_begin(aio) != 0) {
+ return;
+ }
+ nni_mtx_lock(&ws->mtx);
+ if ((rv = nni_aio_schedule(aio, ws_read_cancel, ws)) != 0) {
+ nni_mtx_unlock(&ws->mtx);
+ nni_aio_finish_error(aio, rv);
+ return;
+ }
+ nni_list_append(&ws->recvq, aio);
+ if (nni_list_first(&ws->recvq) == aio) {
+ ws_read_finish_msg(ws);
+ }
+ ws_start_read(ws);
+
+ nni_mtx_unlock(&ws->mtx);
+}
+
+static int
+ws_get_request_headers(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws *ws = arg;
+ nni_mtx_lock(&ws->mtx);
+ if (ws->reqhdrs == NULL) {
+ ws->reqhdrs = nni_http_req_headers(ws->req);
+ }
+ nni_mtx_unlock(&ws->mtx);
+ return (nni_copyout_str(ws->reqhdrs, buf, szp, t));
+}
+
+static int
+ws_get_response_headers(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws *ws = arg;
+ nni_mtx_lock(&ws->mtx);
+ if (ws->reshdrs == NULL) {
+ ws->reshdrs = nni_http_res_headers(ws->res);
+ }
+ nni_mtx_unlock(&ws->mtx);
+ return (nni_copyout_str(ws->reshdrs, buf, szp, t));
+}
+
+static int
+ws_get_request_uri(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws *ws = arg;
+ return (nni_copyout_str(nni_http_req_get_uri(ws->req), buf, szp, t));
+}
+
+static const nni_option ws_options[] = {
+ {
+ .o_name = NNG_OPT_WS_REQUEST_HEADERS,
+ .o_get = ws_get_request_headers,
+ },
+ {
+ .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
+ .o_get = ws_get_response_headers,
+ },
+ {
+ .o_name = NNG_OPT_WS_REQUEST_URI,
+ .o_get = ws_get_request_uri,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+ws_str_setx(void *arg, const char *nm, const void *buf, size_t sz, nni_type t)
+{
+ nni_ws *ws = arg;
+ int rv;
+
+ // Headers can only be set.
+ nni_mtx_lock(&ws->mtx);
+ if (ws->closed) {
+ nni_mtx_unlock(&ws->mtx);
+ return (NNG_ECLOSED);
+ }
+ nni_mtx_unlock(&ws->mtx);
+ rv = nni_http_conn_setopt(ws->http, nm, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_setopt(ws_options, nm, ws, buf, sz, t);
+ }
+ if (rv == NNG_ENOTSUP) {
+ if (startswith(nm, NNG_OPT_WS_REQUEST_HEADER) ||
+ startswith(nm, NNG_OPT_WS_RESPONSE_HEADER)) {
+ return (NNG_EREADONLY);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ws_get_req_header(
+ nni_ws *ws, const char *nm, void *buf, size_t *szp, nni_type t)
+{
+ const char *s;
+ nm += strlen(NNG_OPT_WS_REQUEST_HEADER);
+ s = nni_http_req_get_header(ws->req, nm);
+ if (s == NULL) {
+ return (NNG_ENOENT);
+ }
+ return (nni_copyout_str(s, buf, szp, t));
+}
+
+static int
+ws_get_res_header(
+ nni_ws *ws, const char *nm, void *buf, size_t *szp, nni_type t)
+{
+ const char *s;
+ nm += strlen(NNG_OPT_WS_RESPONSE_HEADER);
+ s = nni_http_res_get_header(ws->res, nm);
+ if (s == NULL) {
+ return (NNG_ENOENT);
+ }
+ return (nni_copyout_str(s, buf, szp, t));
+}
+
+static int
+ws_str_getx(void *arg, const char *nm, void *buf, size_t *szp, nni_type t)
+{
+ nni_ws *ws = arg;
+ int rv;
+
+ nni_mtx_lock(&ws->mtx);
+ if (ws->closed) {
+ nni_mtx_unlock(&ws->mtx);
+ return (NNG_ECLOSED);
+ }
+ nni_mtx_unlock(&ws->mtx);
+ rv = nni_http_conn_getopt(ws->http, nm, buf, szp, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_getopt(ws_options, nm, ws, buf, szp, t);
+ }
+ // Check for generic headers...
+ if (rv == NNG_ENOTSUP) {
+ if (startswith(nm, NNG_OPT_WS_REQUEST_HEADER)) {
+ rv = ws_get_req_header(ws, nm, buf, szp, t);
+ } else if (startswith(nm, NNG_OPT_WS_RESPONSE_HEADER)) {
+ rv = ws_get_res_header(ws, nm, buf, szp, t);
+ }
+ }
+ return (rv);
+}
+
+static int
+ws_check_size(const void *buf, size_t sz, nni_type t)
+{
+ return (nni_copyin_size(NULL, buf, sz, 0, NNI_MAXSZ, t));
+}
+
+static const nni_chkoption ws_chkopts[] = {
+ {
+ .o_name = NNG_OPT_WS_SENDMAXFRAME,
+ .o_check = ws_check_size,
+ },
+ {
+ .o_name = NNG_OPT_WS_RECVMAXFRAME,
+ .o_check = ws_check_size,
+ },
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_check = ws_check_size,
+ },
+ {
+ .o_name = NNG_OPT_WS_PROTOCOL,
+ .o_check = ws_check_string,
+ },
+ {
+ .o_name = NNG_OPT_WS_REQUEST_HEADERS,
+ .o_check = ws_check_string,
+ },
+ {
+ .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
+ .o_check = ws_check_string,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+int
+nni_ws_checkopt(const char *name, const void *data, size_t sz, nni_type t)
+{
+ int rv;
+
+ rv = nni_chkopt(ws_chkopts, name, data, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("tcp", name, data, sz, t);
+ }
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("tls+tcp", name, data, sz, t);
+ }
+ if (rv == NNG_ENOTSUP) {
+ if (startswith(name, NNG_OPT_WS_REQUEST_HEADER) ||
+ startswith(name, NNG_OPT_WS_RESPONSE_HEADER)) {
+ rv = ws_check_string(data, sz, t);
+ }
+ }
+ // Potentially, add checks for header options.
+ return (rv);
+}
diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h
index 88b4bfb4..bbc58d30 100644
--- a/src/supplemental/websocket/websocket.h
+++ b/src/supplemental/websocket/websocket.h
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -18,7 +18,10 @@ typedef struct nni_ws nni_ws;
typedef struct nni_ws_listener nni_ws_listener;
typedef struct nni_ws_dialer nni_ws_dialer;
-typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *);
+// Internal option, not for normal use (at present). This sets the
+// dialer/listener into message mode. This is used by the SP transport.
+// This is a boolean.
+#define NNI_OPT_WS_MSGMODE "ws:msgmode"
// Specify URL as ws://[<host>][:port][/path]
// If host is missing, INADDR_ANY is assumed. If port is missing,
@@ -26,44 +29,10 @@ typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *);
// on INADDR_ANY port 80, with path "/". For connect side, INADDR_ANY
// makes no sense. (TBD: return NNG_EADDRINVAL, or try loopback?)
-extern int nni_ws_listener_init(nni_ws_listener **, nni_url *);
-extern void nni_ws_listener_fini(nni_ws_listener *);
-extern void nni_ws_listener_close(nni_ws_listener *);
-extern int nni_ws_listener_proto(nni_ws_listener *, const char *);
-extern int nni_ws_listener_listen(nni_ws_listener *);
-extern void nni_ws_listener_accept(nni_ws_listener *, nng_aio *);
-extern void nni_ws_listener_hook(
- nni_ws_listener *, nni_ws_listen_hook, void *);
-extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *);
-extern int nni_ws_listener_get_tls(nni_ws_listener *, nng_tls_config **s);
-extern void nni_ws_listener_set_maxframe(nni_ws_listener *, size_t);
-
-extern int nni_ws_dialer_init(nni_ws_dialer **, nni_url *);
-extern void nni_ws_dialer_fini(nni_ws_dialer *);
-extern void nni_ws_dialer_close(nni_ws_dialer *);
-extern int nni_ws_dialer_proto(nni_ws_dialer *, const char *);
-extern int nni_ws_dialer_header(nni_ws_dialer *, const char *, const char *);
-extern void nni_ws_dialer_set_maxframe(nni_ws_dialer *, size_t);
-extern void nni_ws_dialer_dial(nni_ws_dialer *, nng_aio *);
-extern int nni_ws_dialer_set_tls(nni_ws_dialer *, nng_tls_config *);
-extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **);
-
-// Dialer does not get a hook chance, as it can examine the request and reply
-// after dial is done; this is not a 3-way handshake, so the dialer does
-// not confirm the server's response at the HTTP level. (It can still issue
-// a websocket close).
-
-extern void nni_ws_send_msg(nni_ws *, nng_aio *);
-extern void nni_ws_recv_msg(nni_ws *, nng_aio *);
-extern void nni_ws_close(nni_ws *);
-extern void nni_ws_close_error(nni_ws *, uint16_t);
-extern void nni_ws_fini(nni_ws *);
-extern const char *nni_ws_response_headers(nni_ws *);
-extern const char *nni_ws_request_headers(nni_ws *);
-extern int nni_ws_getopt(nni_ws *, const char *, void *, size_t *, nni_type);
-extern int nni_ws_setopt(
- nni_ws *, const char *, const void *, size_t, nni_type);
-
-// The implementation will send periodic PINGs, and respond with PONGs.
+// Much of the websocket API is still "private", meeaning you should not
+// rely upon it being around.
+extern int nni_ws_listener_alloc(nng_stream_listener **, const nni_url *);
+extern int nni_ws_dialer_alloc(nng_stream_dialer **, const nni_url *);
+extern int nni_ws_checkopt(const char *, const void *, size_t, nni_type);
#endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H
diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c
index 609b1811..e0d83be0 100644
--- a/src/transport/ipc/ipc.c
+++ b/src/transport/ipc/ipc.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -27,7 +27,7 @@ typedef struct ipctran_ep ipctran_ep;
// ipc_pipe is one end of an IPC connection.
struct ipctran_pipe {
- nni_ipc_conn * conn;
+ nng_stream * conn;
uint16_t peer;
uint16_t proto;
size_t rcvmax;
@@ -58,17 +58,17 @@ struct ipctran_pipe {
};
struct ipctran_ep {
- nni_mtx mtx;
- nni_sockaddr sa;
- size_t rcvmax;
- uint16_t proto;
- nni_list pipes;
- bool fini;
- nni_ipc_dialer * dialer;
- nni_ipc_listener *listener;
- nni_reap_item reap;
- nni_dialer * ndialer;
- nni_listener * nlistener;
+ nni_mtx mtx;
+ nni_sockaddr sa;
+ size_t rcvmax;
+ uint16_t proto;
+ nni_list pipes;
+ bool fini;
+ nng_stream_dialer * dialer;
+ nng_stream_listener *listener;
+ nni_reap_item reap;
+ nni_dialer * ndialer;
+ nni_listener * nlistener;
};
static void ipctran_pipe_send_start(ipctran_pipe *);
@@ -104,7 +104,7 @@ ipctran_pipe_close(void *arg)
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_ipc_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
static void
@@ -145,9 +145,7 @@ ipctran_pipe_fini(void *arg)
nni_aio_fini(p->txaio);
nni_aio_fini(p->negoaio);
nni_aio_fini(p->connaio);
- if (p->conn != NULL) {
- nni_ipc_conn_fini(p->conn);
- }
+ nng_stream_free(p->conn);
if (p->rxmsg) {
nni_msg_free(p->rxmsg);
}
@@ -160,7 +158,7 @@ ipctran_pipe_reap(ipctran_pipe *p)
{
if (!nni_atomic_flag_test_and_set(&p->reaped)) {
if (p->conn != NULL) {
- nni_ipc_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
nni_reap(&p->reap, ipctran_pipe_fini, p);
}
@@ -195,7 +193,6 @@ ipctran_pipe_alloc(ipctran_pipe **pipep, ipctran_ep *ep)
p->proto = ep->proto;
p->rcvmax = ep->rcvmax;
- p->sa = ep->sa;
p->ep = ep;
*pipep = p;
@@ -244,7 +241,7 @@ ipctran_pipe_conn_cb(void *arg)
iov.iov_len = 8;
iov.iov_buf = &p->txhead[0];
nni_aio_set_iov(p->negoaio, 1, &iov);
- nni_ipc_conn_send(p->conn, p->negoaio);
+ nng_stream_send(p->conn, p->negoaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -278,7 +275,7 @@ ipctran_pipe_nego_cb(void *arg)
iov.iov_buf = &p->txhead[p->gottxhead];
nni_aio_set_iov(aio, 1, &iov);
// send it down...
- nni_ipc_conn_send(p->conn, aio);
+ nng_stream_send(p->conn, aio);
nni_mtx_unlock(&p->ep->mtx);
return;
}
@@ -287,7 +284,7 @@ ipctran_pipe_nego_cb(void *arg)
iov.iov_len = p->wantrxhead - p->gotrxhead;
iov.iov_buf = &p->rxhead[p->gotrxhead];
nni_aio_set_iov(aio, 1, &iov);
- nni_ipc_conn_recv(p->conn, aio);
+ nng_stream_recv(p->conn, aio);
nni_mtx_unlock(&p->ep->mtx);
return;
}
@@ -343,7 +340,7 @@ ipctran_pipe_send_cb(void *arg)
n = nni_aio_count(txaio);
nni_aio_iov_advance(txaio, n);
if (nni_aio_iov_count(txaio) != 0) {
- nni_ipc_conn_send(p->conn, txaio);
+ nng_stream_send(p->conn, txaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -385,7 +382,7 @@ ipctran_pipe_recv_cb(void *arg)
nni_aio_iov_advance(rxaio, n);
if (nni_aio_iov_count(rxaio) != 0) {
// Was this a partial read? If so then resubmit for the rest.
- nni_ipc_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -429,7 +426,7 @@ ipctran_pipe_recv_cb(void *arg)
iov.iov_len = (size_t) len;
nni_aio_set_iov(rxaio, 1, &iov);
- nni_ipc_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -531,7 +528,7 @@ ipctran_pipe_send_start(ipctran_pipe *p)
niov++;
}
nni_aio_set_iov(txaio, niov, iov);
- nni_ipc_conn_send(p->conn, txaio);
+ nng_stream_send(p->conn, txaio);
}
static void
@@ -604,7 +601,7 @@ ipctran_pipe_recv_start(ipctran_pipe *p)
iov.iov_len = sizeof(p->rxhead);
nni_aio_set_iov(rxaio, 1, &iov);
- nni_ipc_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
}
static void
@@ -670,12 +667,8 @@ ipctran_ep_fini(void *arg)
nni_mtx_unlock(&ep->mtx);
return;
}
- if (ep->dialer != NULL) {
- nni_ipc_dialer_fini(ep->dialer);
- }
- if (ep->listener != NULL) {
- nni_ipc_listener_fini(ep->listener);
- }
+ nng_stream_dialer_free(ep->dialer);
+ nng_stream_listener_free(ep->listener);
nni_mtx_unlock(&ep->mtx);
nni_mtx_fini(&ep->mtx);
NNI_FREE_STRUCT(ep);
@@ -694,14 +687,14 @@ ipctran_ep_close(void *arg)
nni_aio_close(p->txaio);
nni_aio_close(p->rxaio);
if (p->conn != NULL) {
- nni_ipc_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
}
if (ep->dialer != NULL) {
- nni_ipc_dialer_close(ep->dialer);
+ nng_stream_dialer_close(ep->dialer);
}
if (ep->listener != NULL) {
- nni_ipc_listener_close(ep->listener);
+ nng_stream_listener_close(ep->listener);
}
nni_mtx_unlock(&ep->mtx);
}
@@ -711,7 +704,6 @@ ipctran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
{
ipctran_ep *ep;
int rv;
- size_t sz;
nni_sock * sock = nni_dialer_sock(ndialer);
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
@@ -720,17 +712,10 @@ ipctran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->pipes, ipctran_pipe, node);
- sz = sizeof(ep->sa.s_ipc.sa_path);
- ep->sa.s_ipc.sa_family = NNG_AF_IPC;
- ep->proto = nni_sock_proto_id(sock);
- ep->ndialer = ndialer;
-
- if (nni_strlcpy(ep->sa.s_ipc.sa_path, url->u_path, sz) >= sz) {
- ipctran_ep_fini(ep);
- return (NNG_EADDRINVAL);
- }
+ ep->proto = nni_sock_proto_id(sock);
+ ep->ndialer = ndialer;
- if ((rv = nni_ipc_dialer_init(&ep->dialer)) != 0) {
+ if ((rv = nng_stream_dialer_alloc_url(&ep->dialer, url)) != 0) {
ipctran_ep_fini(ep);
return (rv);
}
@@ -744,7 +729,6 @@ ipctran_ep_init_listener(void **dp, nni_url *url, nni_listener *nlistener)
{
ipctran_ep *ep;
int rv;
- size_t sz;
nni_sock * sock = nni_listener_sock(nlistener);
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
@@ -753,17 +737,10 @@ ipctran_ep_init_listener(void **dp, nni_url *url, nni_listener *nlistener)
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->pipes, ipctran_pipe, node);
- sz = sizeof(ep->sa.s_ipc.sa_path);
- ep->sa.s_ipc.sa_family = NNG_AF_IPC;
- ep->proto = nni_sock_proto_id(sock);
- ep->nlistener = nlistener;
+ ep->proto = nni_sock_proto_id(sock);
+ ep->nlistener = nlistener;
- if (nni_strlcpy(ep->sa.s_ipc.sa_path, url->u_path, sz) >= sz) {
- ipctran_ep_fini(ep);
- return (NNG_EADDRINVAL);
- }
-
- if ((rv = nni_ipc_listener_init(&ep->listener)) != 0) {
+ if ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0) {
ipctran_ep_fini(ep);
return (rv);
}
@@ -797,7 +774,7 @@ ipctran_ep_connect(void *arg, nni_aio *aio)
return;
}
p->useraio = aio;
- nni_ipc_dialer_dial(ep->dialer, &p->sa, p->connaio);
+ nng_stream_dialer_dial(ep->dialer, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -839,7 +816,7 @@ ipctran_ep_bind(void *arg)
int rv;
nni_mtx_lock(&ep->mtx);
- rv = nni_ipc_listener_listen(ep->listener, &ep->sa);
+ rv = nng_stream_listener_listen(ep->listener);
nni_mtx_unlock(&ep->mtx);
return (rv);
}
@@ -869,7 +846,7 @@ ipctran_ep_accept(void *arg, nni_aio *aio)
return;
}
p->useraio = aio;
- nni_ipc_listener_accept(ep->listener, p->connaio);
+ nng_stream_listener_accept(ep->listener, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -879,8 +856,7 @@ ipctran_pipe_getopt(
{
ipctran_pipe *p = arg;
- // We defer to the platform getopt code for IPC connections.
- return (nni_ipc_conn_getopt(p->conn, name, buf, szp, t));
+ return (nni_stream_getx(p->conn, name, buf, szp, t));
}
static nni_tran_pipe_ops ipctran_pipe_ops = {
@@ -915,7 +891,7 @@ ipctran_dialer_getopt(
rv = nni_getopt(ipctran_ep_options, name, ep, buf, szp, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_ipc_dialer_getopt(ep->dialer, name, buf, szp, t);
+ rv = nni_stream_dialer_getx(ep->dialer, name, buf, szp, t);
}
return (rv);
}
@@ -929,8 +905,7 @@ ipctran_dialer_setopt(
rv = nni_setopt(ipctran_ep_options, name, ep, buf, sz, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_ipc_dialer_setopt(
- ep != NULL ? ep->dialer : NULL, name, buf, sz, t);
+ rv = nni_stream_dialer_setx(ep->dialer, name, buf, sz, t);
}
return (rv);
}
@@ -944,7 +919,7 @@ ipctran_listener_getopt(
rv = nni_getopt(ipctran_ep_options, name, ep, buf, szp, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_ipc_listener_getopt(ep->listener, name, buf, szp, t);
+ rv = nni_stream_listener_getx(ep->listener, name, buf, szp, t);
}
return (rv);
}
@@ -958,8 +933,34 @@ ipctran_listener_setopt(
rv = nni_setopt(ipctran_ep_options, name, ep, buf, sz, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_ipc_listener_setopt(
- ep != NULL ? ep->listener : NULL, name, buf, sz, t);
+ rv = nni_stream_listener_setx(ep->listener, name, buf, sz, t);
+ }
+ return (rv);
+}
+
+static int
+ipctran_check_recvmaxsz(const void *v, size_t sz, nni_type t)
+{
+ return (nni_copyin_size(NULL, v, sz, 0, NNI_MAXSZ, t));
+}
+
+static nni_chkoption ipctran_checkopts[] = {
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_check = ipctran_check_recvmaxsz,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+ipctran_checkopt(const char *name, const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ rv = nni_chkopt(ipctran_checkopts, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("ipc", name, buf, sz, t);
}
return (rv);
}
@@ -991,6 +992,7 @@ static nni_tran ipc_tran = {
.tran_pipe = &ipctran_pipe_ops,
.tran_init = ipctran_init,
.tran_fini = ipctran_fini,
+ .tran_checkopt = ipctran_checkopt,
};
int
diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c
index 30695918..3d757ee7 100644
--- a/src/transport/tcp/tcp.c
+++ b/src/transport/tcp/tcp.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -14,6 +14,7 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "core/tcp.h"
// TCP transport. Platform specific TCP operations must be
// supplied as well.
@@ -23,19 +24,16 @@ typedef struct tcptran_ep tcptran_ep;
// tcp_pipe is one end of a TCP connection.
struct tcptran_pipe {
- nni_tcp_conn * conn;
+ nng_stream * conn;
nni_pipe * npipe;
uint16_t peer;
uint16_t proto;
size_t rcvmax;
- bool nodelay;
- bool keepalive;
bool closed;
nni_list_node node;
tcptran_ep * ep;
nni_atomic_flag reaped;
nni_reap_item reap;
- nni_sockaddr sa;
uint8_t txlen[sizeof(uint64_t)];
uint8_t rxlen[sizeof(uint64_t)];
size_t gottxhead;
@@ -49,30 +47,25 @@ struct tcptran_pipe {
nni_aio * rxaio;
nni_aio * negoaio;
nni_aio * connaio;
- nni_aio * rslvaio;
nni_msg * rxmsg;
nni_mtx mtx;
};
struct tcptran_ep {
- nni_mtx mtx;
- uint16_t af;
- uint16_t proto;
- size_t rcvmax;
- bool nodelay;
- bool keepalive;
- bool fini;
- nni_url * url;
- const char * host; // for dialers
- nng_sockaddr src;
- nng_sockaddr sa;
- nng_sockaddr bsa;
- nni_list pipes;
- nni_reap_item reap;
- nni_tcp_dialer * dialer;
- nni_tcp_listener *listener;
- nni_dialer * ndialer;
- nni_listener * nlistener;
+ nni_mtx mtx;
+ uint16_t af;
+ uint16_t proto;
+ size_t rcvmax;
+ bool fini;
+ nni_url * url;
+ const char * host; // for dialers
+ nng_sockaddr src;
+ nni_list pipes;
+ nni_reap_item reap;
+ nng_stream_dialer * dialer;
+ nng_stream_listener *listener;
+ nni_dialer * ndialer;
+ nni_listener * nlistener;
};
static void tcptran_pipe_send_start(tcptran_pipe *);
@@ -81,7 +74,6 @@ static void tcptran_pipe_send_cb(void *);
static void tcptran_pipe_recv_cb(void *);
static void tcptran_pipe_conn_cb(void *);
static void tcptran_pipe_nego_cb(void *);
-static void tcptran_pipe_rslv_cb(void *);
static void tcptran_ep_fini(void *);
static int
@@ -108,9 +100,8 @@ tcptran_pipe_close(void *arg)
nni_aio_close(p->txaio);
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
- nni_tcp_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
static void
@@ -122,7 +113,6 @@ tcptran_pipe_stop(void *arg)
nni_aio_stop(p->txaio);
nni_aio_stop(p->negoaio);
nni_aio_stop(p->connaio);
- nni_aio_stop(p->rslvaio);
}
static int
@@ -153,10 +143,7 @@ tcptran_pipe_fini(void *arg)
nni_aio_fini(p->txaio);
nni_aio_fini(p->negoaio);
nni_aio_fini(p->connaio);
- nni_aio_fini(p->rslvaio);
- if (p->conn != NULL) {
- nni_tcp_conn_fini(p->conn);
- }
+ nng_stream_free(p->conn);
nni_msg_free(p->rxmsg);
nni_mtx_fini(&p->mtx);
NNI_FREE_STRUCT(p);
@@ -167,7 +154,7 @@ tcptran_pipe_reap(tcptran_pipe *p)
{
if (!nni_atomic_flag_test_and_set(&p->reaped)) {
if (p->conn != NULL) {
- nni_tcp_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
nni_reap(&p->reap, tcptran_pipe_fini, p);
}
@@ -185,7 +172,6 @@ tcptran_pipe_alloc(tcptran_pipe **pipep, tcptran_ep *ep)
nni_mtx_init(&p->mtx);
if (((rv = nni_aio_init(&p->txaio, tcptran_pipe_send_cb, p)) != 0) ||
((rv = nni_aio_init(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) ||
- ((rv = nni_aio_init(&p->rslvaio, tcptran_pipe_rslv_cb, p)) != 0) ||
((rv = nni_aio_init(&p->connaio, tcptran_pipe_conn_cb, p)) != 0) ||
((rv = nni_aio_init(&p->negoaio, tcptran_pipe_nego_cb, p)) != 0)) {
tcptran_pipe_fini(p);
@@ -196,12 +182,10 @@ tcptran_pipe_alloc(tcptran_pipe **pipep, tcptran_ep *ep)
nni_atomic_flag_reset(&p->reaped);
nni_list_append(&ep->pipes, p);
- p->keepalive = ep->keepalive;
- p->nodelay = ep->nodelay;
- p->rcvmax = ep->rcvmax;
- p->proto = ep->proto;
- p->ep = ep;
- *pipep = p;
+ p->rcvmax = ep->rcvmax;
+ p->proto = ep->proto;
+ p->ep = ep;
+ *pipep = p;
return (0);
}
@@ -215,7 +199,6 @@ tcptran_pipe_conn_cancel(nni_aio *aio, void *arg, int rv)
if (aio == p->useraio) {
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
p->useraio = NULL;
nni_aio_finish_error(aio, rv);
tcptran_pipe_reap(p);
@@ -224,33 +207,6 @@ tcptran_pipe_conn_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-tcptran_pipe_rslv_cb(void *arg)
-{
- tcptran_pipe *p = arg;
- tcptran_ep * ep = p->ep;
- nni_aio * aio = p->rslvaio;
- nni_aio * uaio;
- int rv;
-
- nni_mtx_lock(&ep->mtx);
- if ((uaio = p->useraio) == NULL) {
- nni_mtx_unlock(&ep->mtx);
- tcptran_pipe_reap(p);
- return;
- }
- if ((rv = nni_aio_result(aio)) != 0) {
- p->useraio = NULL;
- nni_mtx_unlock(&ep->mtx);
- nni_aio_finish_error(uaio, rv);
- tcptran_pipe_reap(p);
- return;
- }
-
- nni_tcp_dialer_dial(ep->dialer, &p->sa, p->connaio);
- nni_mtx_unlock(&ep->mtx);
-}
-
-static void
tcptran_pipe_conn_cb(void *arg)
{
tcptran_pipe *p = arg;
@@ -293,7 +249,7 @@ tcptran_pipe_conn_cb(void *arg)
iov.iov_len = 8;
iov.iov_buf = &p->txlen[0];
nni_aio_set_iov(p->negoaio, 1, &iov);
- nni_tcp_conn_send(p->conn, p->negoaio);
+ nng_stream_send(p->conn, p->negoaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -330,7 +286,7 @@ tcptran_pipe_nego_cb(void *arg)
iov.iov_buf = &p->txlen[p->gottxhead];
// send it down...
nni_aio_set_iov(aio, 1, &iov);
- nni_tcp_conn_send(p->conn, aio);
+ nng_stream_send(p->conn, aio);
nni_mtx_unlock(&ep->mtx);
return;
}
@@ -339,7 +295,7 @@ tcptran_pipe_nego_cb(void *arg)
iov.iov_len = p->wantrxhead - p->gotrxhead;
iov.iov_buf = &p->rxlen[p->gotrxhead];
nni_aio_set_iov(aio, 1, &iov);
- nni_tcp_conn_recv(p->conn, aio);
+ nng_stream_recv(p->conn, aio);
nni_mtx_unlock(&ep->mtx);
return;
}
@@ -354,10 +310,6 @@ tcptran_pipe_nego_cb(void *arg)
NNI_GET16(&p->rxlen[4], p->peer);
p->useraio = NULL;
- (void) nni_tcp_conn_setopt(p->conn, NNG_OPT_TCP_NODELAY, &p->nodelay,
- sizeof(p->nodelay), NNI_TYPE_BOOL);
- (void) nni_tcp_conn_setopt(p->conn, NNG_OPT_TCP_KEEPALIVE,
- &p->keepalive, sizeof(p->keepalive), NNI_TYPE_BOOL);
nni_mtx_unlock(&ep->mtx);
@@ -400,7 +352,7 @@ tcptran_pipe_send_cb(void *arg)
n = nni_aio_count(txaio);
nni_aio_iov_advance(txaio, n);
if (nni_aio_iov_count(txaio) > 0) {
- nni_tcp_conn_send(p->conn, txaio);
+ nng_stream_send(p->conn, txaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -437,7 +389,7 @@ tcptran_pipe_recv_cb(void *arg)
n = nni_aio_count(rxaio);
nni_aio_iov_advance(rxaio, n);
if (nni_aio_iov_count(rxaio) > 0) {
- nni_tcp_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -469,7 +421,7 @@ tcptran_pipe_recv_cb(void *arg)
iov.iov_len = (size_t) len;
nni_aio_set_iov(rxaio, 1, &iov);
- nni_tcp_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -566,7 +518,7 @@ tcptran_pipe_send_start(tcptran_pipe *p)
niov++;
}
nni_aio_set_iov(txaio, niov, iov);
- nni_tcp_conn_send(p->conn, txaio);
+ nng_stream_send(p->conn, txaio);
}
static void
@@ -639,7 +591,7 @@ tcptran_pipe_recv_start(tcptran_pipe *p)
iov.iov_len = sizeof(p->rxlen);
nni_aio_set_iov(rxaio, 1, &iov);
- nni_tcp_conn_recv(p->conn, rxaio);
+ nng_stream_recv(p->conn, rxaio);
}
static void
@@ -678,7 +630,7 @@ tcptran_pipe_getopt(
void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
tcptran_pipe *p = arg;
- return (nni_tcp_conn_getopt(p->conn, name, buf, szp, t));
+ return (nni_stream_getx(p->conn, name, buf, szp, t));
}
static void
@@ -692,12 +644,8 @@ tcptran_ep_fini(void *arg)
nni_mtx_unlock(&ep->mtx);
return;
}
- if (ep->dialer != NULL) {
- nni_tcp_dialer_fini(ep->dialer);
- }
- if (ep->listener != NULL) {
- nni_tcp_listener_fini(ep->listener);
- }
+ nng_stream_dialer_free(ep->dialer);
+ nng_stream_listener_free(ep->listener);
nni_mtx_unlock(&ep->mtx);
nni_mtx_fini(&ep->mtx);
NNI_FREE_STRUCT(ep);
@@ -713,41 +661,89 @@ tcptran_ep_close(void *arg)
NNI_LIST_FOREACH (&ep->pipes, p) {
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
nni_aio_close(p->txaio);
nni_aio_close(p->rxaio);
if (p->conn != NULL) {
- nni_tcp_conn_close(p->conn);
+ nng_stream_close(p->conn);
}
}
if (ep->dialer != NULL) {
- nni_tcp_dialer_close(ep->dialer);
+ nng_stream_dialer_close(ep->dialer);
}
if (ep->listener != NULL) {
- nni_tcp_listener_close(ep->listener);
+ nng_stream_listener_close(ep->listener);
}
nni_mtx_unlock(&ep->mtx);
}
+// This parses off the optional source address that this transport uses.
+// The special handling of this URL format is quite honestly an historical
+// mistake, which we would remove if we could.
static int
-tcptran_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
+tcptran_url_parse_source(nni_url *url, nng_sockaddr *sa, const nni_url *surl)
{
- tcptran_ep * ep;
- int rv;
- uint16_t af;
- char * host;
- nng_sockaddr srcsa;
- nni_sock * sock = nni_dialer_sock(ndialer);
+ int af;
+ char * semi;
+ char * src;
+ size_t len;
+ int rv;
+ nni_aio *aio;
+
+ // We modify the URL. This relies on the fact that the underlying
+ // transport does not free this, so we can just use references.
+
+ url->u_scheme = surl->u_scheme;
+ url->u_port = surl->u_port;
+ url->u_hostname = surl->u_hostname;
+
+ if ((semi = strchr(url->u_hostname, ';')) == NULL) {
+ memset(sa, 0, sizeof(*sa));
+ return (0);
+ }
- if (strcmp(url->u_scheme, "tcp") == 0) {
+ len = (size_t)(semi - url->u_hostname);
+ url->u_hostname = semi + 1;
+
+ if (strcmp(surl->u_scheme, "tcp") == 0) {
af = NNG_AF_UNSPEC;
- } else if (strcmp(url->u_scheme, "tcp4") == 0) {
+ } else if (strcmp(surl->u_scheme, "tcp4") == 0) {
af = NNG_AF_INET;
- } else if (strcmp(url->u_scheme, "tcp6") == 0) {
+ } else if (strcmp(surl->u_scheme, "tcp6") == 0) {
af = NNG_AF_INET6;
} else {
return (NNG_EADDRINVAL);
}
+
+ if ((src = nni_alloc(len + 1)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ memcpy(src, surl->u_hostname, len);
+ src[len] = '\0';
+
+ if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
+ nni_free(src, len + 1);
+ return (rv);
+ }
+
+ nni_tcp_resolv(src, 0, af, 1, aio);
+ nni_aio_wait(aio);
+ if ((rv = nni_aio_result(aio)) == 0) {
+ nni_aio_get_sockaddr(aio, sa);
+ }
+ nni_aio_fini(aio);
+ nni_free(src, len + 1);
+ return (rv);
+}
+
+static int
+tcptran_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
+{
+ tcptran_ep * ep;
+ int rv;
+ nng_sockaddr srcsa;
+ nni_sock * sock = nni_dialer_sock(ndialer);
+ nni_url myurl;
+
// Check for invalid URL components.
if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) {
return (NNG_EADDRINVAL);
@@ -758,62 +754,27 @@ tcptran_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
return (NNG_EADDRINVAL);
}
+ if ((rv = tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) {
+ return (NNG_EADDRINVAL);
+ }
+
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
return (NNG_ENOMEM);
}
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->pipes, tcptran_pipe, node);
- ep->af = af;
- ep->proto = nni_sock_proto_id(sock);
- ep->nodelay = true;
- ep->keepalive = false;
- ep->url = url;
- ep->ndialer = ndialer;
-
- // Detect an embedded local interface name in the hostname. This
- // syntax is only valid with dialers.
- if ((host = strchr(url->u_hostname, ';')) != NULL) {
- size_t len;
- char * src = NULL;
- nni_aio *aio;
- len = (uintptr_t) host - (uintptr_t) url->u_hostname;
- host++;
- if ((len < 2) || (strlen(host) == 0)) {
- tcptran_ep_fini(ep);
- return (NNG_EADDRINVAL);
- }
- if ((src = nni_alloc(len + 1)) == NULL) {
- tcptran_ep_fini(ep);
- return (NNG_ENOMEM);
- }
- memcpy(src, url->u_hostname, len);
- src[len] = 0;
-
- if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
- tcptran_ep_fini(ep);
- nni_strfree(src);
- return (rv);
- }
- nni_aio_set_input(aio, 0, &srcsa);
- nni_tcp_resolv(src, 0, af, 1, aio);
- nni_aio_wait(aio);
- rv = nni_aio_result(aio);
- nni_aio_fini(aio);
- nni_strfree(src);
- ep->host = host;
- } else {
- srcsa.s_family = NNG_AF_UNSPEC;
- ep->host = url->u_hostname;
- rv = 0;
- }
+ ep->proto = nni_sock_proto_id(sock);
+ ep->url = url;
+ ep->ndialer = ndialer;
- if ((rv != 0) || ((rv = nni_tcp_dialer_init(&ep->dialer)) != 0)) {
+ if ((rv != 0) ||
+ ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) {
tcptran_ep_fini(ep);
return (rv);
}
if ((srcsa.s_family != NNG_AF_UNSPEC) &&
- ((rv = nni_tcp_dialer_setopt(ep->dialer, NNG_OPT_LOCADDR, &srcsa,
+ ((rv = nni_stream_dialer_setx(ep->dialer, NNG_OPT_LOCADDR, &srcsa,
sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) {
tcptran_ep_fini(ep);
return (rv);
@@ -826,21 +787,8 @@ tcptran_listener_init(void **lp, nni_url *url, nni_listener *nlistener)
{
tcptran_ep *ep;
int rv;
- char * host;
- nni_aio * aio;
- uint16_t af;
nni_sock * sock = nni_listener_sock(nlistener);
- if (strcmp(url->u_scheme, "tcp") == 0) {
- af = NNG_AF_UNSPEC;
- } else if (strcmp(url->u_scheme, "tcp4") == 0) {
- af = NNG_AF_INET;
- } else if (strcmp(url->u_scheme, "tcp6") == 0) {
- af = NNG_AF_INET6;
- } else {
- return (NNG_EADDRINVAL);
- }
-
// Check for invalid URL components.
if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) {
return (NNG_EADDRINVAL);
@@ -855,46 +803,14 @@ tcptran_listener_init(void **lp, nni_url *url, nni_listener *nlistener)
}
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->pipes, tcptran_pipe, node);
- ep->af = af;
ep->proto = nni_sock_proto_id(sock);
- ep->nodelay = true;
- ep->keepalive = false;
ep->url = url;
ep->nlistener = nlistener;
- if (strlen(url->u_hostname) == 0) {
- host = NULL;
- } else {
- host = url->u_hostname;
- }
-
- // XXX: We are doing lookup at listener initialization. There is
- // a valid argument that this should be done at bind time, but that
- // would require making bind asynchronous. In some ways this would
- // be worse than the cost of just waiting here. We always recommend
- // using local IP addresses rather than names when possible.
-
- if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
+ if ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0) {
tcptran_ep_fini(ep);
return (rv);
}
- nni_aio_set_input(aio, 0, &ep->sa);
- nni_tcp_resolv(host, url->u_port, af, 1, aio);
- nni_aio_wait(aio);
- rv = nni_aio_result(aio);
- nni_aio_fini(aio);
-
- if (rv != 0) {
- tcptran_ep_fini(ep);
- return (rv);
- }
-
- if ((rv = nni_tcp_listener_init(&ep->listener)) != 0) {
- tcptran_ep_fini(ep);
- return (rv);
- }
-
- ep->bsa = ep->sa;
*lp = ep;
return (0);
@@ -917,17 +833,13 @@ tcptran_ep_connect(void *arg, nni_aio *aio)
return;
}
if ((rv = nni_aio_schedule(aio, tcptran_pipe_conn_cancel, p)) != 0) {
- nni_list_remove(&ep->pipes, p);
- p->ep = NULL;
nni_mtx_unlock(&ep->mtx);
nni_aio_finish_error(aio, rv);
tcptran_pipe_reap(p);
return;
}
p->useraio = aio;
- // Start the name resolution before we try connecting.
- nni_aio_set_input(p->rslvaio, 0, &p->sa);
- nni_tcp_resolv(ep->host, ep->url->u_port, ep->af, 0, p->rslvaio);
+ nng_stream_dialer_dial(ep->dialer, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -941,16 +853,18 @@ tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t)
char ipstr[48]; // max for IPv6 addresses including []
char portstr[6]; // max for 16-bit port
nng_sockaddr sa;
- size_t sz = sizeof(sa);
int rv;
- rv = nni_tcp_listener_getopt(ep->listener, NNG_OPT_LOCADDR,
- &sa, &sz, NNI_TYPE_SOCKADDR);
+ rv = nng_stream_listener_get_addr(
+ ep->listener, NNG_OPT_LOCADDR, &sa);
if (rv != 0) {
return (rv);
}
nni_ntop(&sa, ipstr, portstr);
- snprintf(ustr, sizeof(ustr), "tcp://%s:%s", ipstr, portstr);
+ snprintf(ustr, sizeof(ustr),
+ sa.s_family == NNG_AF_INET6 ? "tcp://[%s]:%s"
+ : "tcp://%s:%s",
+ ipstr, portstr);
return (nni_copyout_str(ustr, v, szp, t));
}
@@ -995,8 +909,7 @@ tcptran_ep_bind(void *arg)
int rv;
nni_mtx_lock(&ep->mtx);
- ep->bsa = ep->sa;
- rv = nni_tcp_listener_listen(ep->listener, &ep->bsa);
+ rv = nng_stream_listener_listen(ep->listener);
nni_mtx_unlock(&ep->mtx);
return (rv);
@@ -1027,7 +940,7 @@ tcptran_ep_accept(void *arg, nni_aio *aio)
return;
}
p->useraio = aio;
- nni_tcp_listener_accept(ep->listener, p->connaio);
+ nng_stream_listener_accept(ep->listener, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -1065,7 +978,7 @@ tcptran_dialer_getopt(
tcptran_ep *ep = arg;
int rv;
- rv = nni_tcp_dialer_getopt(ep->dialer, name, buf, szp, t);
+ rv = nni_stream_dialer_getx(ep->dialer, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t);
}
@@ -1079,8 +992,7 @@ tcptran_dialer_setopt(
tcptran_ep *ep = arg;
int rv;
- rv = nni_tcp_dialer_setopt(
- ep != NULL ? ep->dialer : NULL, name, buf, sz, t);
+ rv = nni_stream_dialer_setx(ep->dialer, name, buf, sz, t);
if (rv == NNG_ENOTSUP) {
rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t);
}
@@ -1094,7 +1006,7 @@ tcptran_listener_getopt(
tcptran_ep *ep = arg;
int rv;
- rv = nni_tcp_listener_getopt(ep->listener, name, buf, szp, t);
+ rv = nni_stream_listener_getx(ep->listener, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t);
}
@@ -1108,14 +1020,40 @@ tcptran_listener_setopt(
tcptran_ep *ep = arg;
int rv;
- rv = nni_tcp_listener_setopt(
- ep != NULL ? ep->listener : NULL, name, buf, sz, t);
+ rv = nni_stream_listener_setx(ep->listener, name, buf, sz, t);
if (rv == NNG_ENOTSUP) {
rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t);
}
return (rv);
}
+static int
+tcptran_check_recvmaxsz(const void *v, size_t sz, nni_type t)
+{
+ return (nni_copyin_size(NULL, v, sz, 0, NNI_MAXSZ, t));
+}
+
+static nni_chkoption tcptran_checkopts[] = {
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_check = tcptran_check_recvmaxsz,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+tcptran_checkopt(const char *name, const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ rv = nni_chkopt(tcptran_checkopts, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("tcp", name, buf, sz, t);
+ }
+ return (rv);
+}
+
static nni_tran_dialer_ops tcptran_dialer_ops = {
.d_init = tcptran_dialer_init,
.d_fini = tcptran_ep_fini,
@@ -1143,6 +1081,7 @@ static nni_tran tcp_tran = {
.tran_pipe = &tcptran_pipe_ops,
.tran_init = tcptran_init,
.tran_fini = tcptran_fini,
+ .tran_checkopt = tcptran_checkopt,
};
static nni_tran tcp4_tran = {
@@ -1153,6 +1092,7 @@ static nni_tran tcp4_tran = {
.tran_pipe = &tcptran_pipe_ops,
.tran_init = tcptran_init,
.tran_fini = tcptran_fini,
+ .tran_checkopt = tcptran_checkopt,
};
static nni_tran tcp6_tran = {
@@ -1163,6 +1103,7 @@ static nni_tran tcp6_tran = {
.tran_pipe = &tcptran_pipe_ops,
.tran_init = tcptran_init,
.tran_fini = tcptran_fini,
+ .tran_checkopt = tcptran_checkopt,
};
int
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c
index 25bfb0dd..d68cb8b1 100644
--- a/src/transport/tls/tls.c
+++ b/src/transport/tls/tls.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -30,7 +30,7 @@ typedef struct tlstran_pipe tlstran_pipe;
// tlstran_pipe is one end of a TLS connection.
struct tlstran_pipe {
- nng_tls * tls;
+ nng_stream * tls;
nni_pipe * npipe;
uint16_t peer;
uint16_t proto;
@@ -54,29 +54,28 @@ struct tlstran_pipe {
nni_aio * rxaio;
nni_aio * negoaio;
nni_aio * connaio;
- nni_aio * rslvaio;
nni_msg * rxmsg;
nni_mtx mtx;
};
// Stuff that is common to both dialers and listeners.
struct tlstran_ep {
- nni_mtx mtx;
- uint16_t af;
- uint16_t proto;
- size_t rcvmax;
- bool fini;
- int authmode;
- nni_url * url;
- nni_list pipes;
- nni_reap_item reap;
- nng_tls_dialer * dialer;
- nng_tls_listener *listener;
- const char * host;
- nng_sockaddr src;
- nng_sockaddr sa;
- nni_dialer * ndialer;
- nni_listener * nlistener;
+ nni_mtx mtx;
+ uint16_t af;
+ uint16_t proto;
+ size_t rcvmax;
+ bool fini;
+ int authmode;
+ nni_url * url;
+ nni_list pipes;
+ nni_reap_item reap;
+ nng_stream_dialer * dialer;
+ nng_stream_listener *listener;
+ const char * host;
+ nng_sockaddr src;
+ nng_sockaddr sa;
+ nni_dialer * ndialer;
+ nni_listener * nlistener;
};
static void tlstran_pipe_send_start(tlstran_pipe *);
@@ -85,7 +84,6 @@ static void tlstran_pipe_send_cb(void *);
static void tlstran_pipe_recv_cb(void *);
static void tlstran_pipe_conn_cb(void *);
static void tlstran_pipe_nego_cb(void *);
-static void tlstran_pipe_rslv_cb(void *);
static void tlstran_ep_fini(void *);
static int
@@ -108,9 +106,8 @@ tlstran_pipe_close(void *arg)
nni_aio_close(p->txaio);
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
- nng_tls_close(p->tls);
+ nng_stream_close(p->tls);
}
static void
@@ -122,7 +119,6 @@ tlstran_pipe_stop(void *arg)
nni_aio_stop(p->txaio);
nni_aio_stop(p->negoaio);
nni_aio_stop(p->connaio);
- nni_aio_stop(p->rslvaio);
}
static int
@@ -152,8 +148,7 @@ tlstran_pipe_fini(void *arg)
nni_aio_fini(p->txaio);
nni_aio_fini(p->negoaio);
nni_aio_fini(p->connaio);
- nni_aio_fini(p->rslvaio);
- nng_tls_free(p->tls);
+ nng_stream_free(p->tls);
nni_msg_free(p->rxmsg);
NNI_FREE_STRUCT(p);
}
@@ -171,7 +166,6 @@ tlstran_pipe_alloc(tlstran_pipe **pipep, tlstran_ep *ep)
if (((rv = nni_aio_init(&p->txaio, tlstran_pipe_send_cb, p)) != 0) ||
((rv = nni_aio_init(&p->rxaio, tlstran_pipe_recv_cb, p)) != 0) ||
- ((rv = nni_aio_init(&p->rslvaio, tlstran_pipe_rslv_cb, p)) != 0) ||
((rv = nni_aio_init(&p->connaio, tlstran_pipe_conn_cb, p)) != 0) ||
((rv = nni_aio_init(&p->negoaio, tlstran_pipe_nego_cb, p)) != 0)) {
tlstran_pipe_fini(p);
@@ -194,7 +188,7 @@ tlstran_pipe_reap(tlstran_pipe *p)
{
if (!nni_atomic_flag_test_and_set(&p->reaped)) {
if (p->tls != NULL) {
- nng_tls_close(p->tls);
+ nng_stream_close(p->tls);
}
nni_reap(&p->reap, tlstran_pipe_fini, p);
}
@@ -210,7 +204,6 @@ tlstran_pipe_conn_cancel(nni_aio *aio, void *arg, int rv)
p->useraio = NULL;
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
nni_aio_finish_error(aio, rv);
tlstran_pipe_reap(p);
}
@@ -218,33 +211,6 @@ tlstran_pipe_conn_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-tlstran_pipe_rslv_cb(void *arg)
-{
- tlstran_pipe *p = arg;
- tlstran_ep * ep = p->ep;
- nni_aio * aio = p->rslvaio;
- nni_aio * uaio;
- int rv;
-
- nni_mtx_lock(&ep->mtx);
- if ((uaio = p->useraio) == NULL) {
- nni_mtx_unlock(&ep->mtx);
- tlstran_pipe_reap(p);
- return;
- }
-
- if ((rv = nni_aio_result(aio)) != 0) {
- p->useraio = NULL;
- nni_mtx_unlock(&ep->mtx);
- nni_aio_finish_error(uaio, rv);
- tlstran_pipe_reap(p);
- return;
- }
- nng_tls_dialer_dial(ep->dialer, &p->sa, p->connaio);
- nni_mtx_unlock(&ep->mtx);
-}
-
-static void
tlstran_pipe_conn_cb(void *arg)
{
tlstran_pipe *p = arg;
@@ -288,7 +254,7 @@ tlstran_pipe_conn_cb(void *arg)
iov.iov_len = 8;
iov.iov_buf = &p->txlen[0];
nni_aio_set_iov(p->negoaio, 1, &iov);
- nng_tls_send(p->tls, p->negoaio);
+ nng_stream_send(p->tls, p->negoaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -325,7 +291,7 @@ tlstran_pipe_nego_cb(void *arg)
iov.iov_buf = &p->txlen[p->gottxhead];
nni_aio_set_iov(aio, 1, &iov);
// send it down...
- nng_tls_send(p->tls, aio);
+ nng_stream_send(p->tls, aio);
nni_mtx_unlock(&ep->mtx);
return;
}
@@ -334,7 +300,7 @@ tlstran_pipe_nego_cb(void *arg)
iov.iov_len = p->wantrxhead - p->gotrxhead;
iov.iov_buf = &p->rxlen[p->gotrxhead];
nni_aio_set_iov(aio, 1, &iov);
- nng_tls_recv(p->tls, aio);
+ nng_stream_recv(p->tls, aio);
nni_mtx_unlock(&ep->mtx);
return;
}
@@ -390,7 +356,7 @@ tlstran_pipe_send_cb(void *arg)
n = nni_aio_count(txaio);
nni_aio_iov_advance(txaio, n);
if (nni_aio_iov_count(txaio) > 0) {
- nng_tls_send(p->tls, txaio);
+ nng_stream_send(p->tls, txaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -426,7 +392,7 @@ tlstran_pipe_recv_cb(void *arg)
nni_aio_iov_advance(rxaio, n);
if (nni_aio_iov_count(rxaio) > 0) {
// Was this a partial read? If so then resubmit for the rest.
- nng_tls_recv(p->tls, rxaio);
+ nng_stream_recv(p->tls, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -458,7 +424,7 @@ tlstran_pipe_recv_cb(void *arg)
iov.iov_len = (size_t) len;
nni_aio_set_iov(rxaio, 1, &iov);
- nng_tls_recv(p->tls, rxaio);
+ nng_stream_recv(p->tls, rxaio);
nni_mtx_unlock(&p->mtx);
return;
}
@@ -548,7 +514,7 @@ tlstran_pipe_send_start(tlstran_pipe *p)
}
nni_aio_set_iov(txaio, niov, iov);
- nng_tls_send(p->tls, txaio);
+ nng_stream_send(p->tls, txaio);
}
static void
@@ -609,7 +575,7 @@ tlstran_pipe_recv_start(tlstran_pipe *p)
iov.iov_len = sizeof(p->rxlen);
nni_aio_set_iov(rxaio, 1, &iov);
- nng_tls_recv(p->tls, rxaio);
+ nng_stream_recv(p->tls, rxaio);
}
static void
@@ -654,8 +620,8 @@ tlstran_ep_fini(void *arg)
nni_mtx_unlock(&ep->mtx);
return;
}
- nng_tls_dialer_free(ep->dialer);
- nng_tls_listener_free(ep->listener);
+ nng_stream_dialer_free(ep->dialer);
+ nng_stream_listener_free(ep->listener);
nni_mtx_unlock(&ep->mtx);
nni_mtx_fini(&ep->mtx);
@@ -672,42 +638,89 @@ tlstran_ep_close(void *arg)
NNI_LIST_FOREACH (&ep->pipes, p) {
nni_aio_close(p->negoaio);
nni_aio_close(p->connaio);
- nni_aio_close(p->rslvaio);
nni_aio_close(p->txaio);
nni_aio_close(p->rxaio);
if (p->tls != NULL) {
- nng_tls_close(p->tls);
+ nng_stream_close(p->tls);
}
}
if (ep->dialer != NULL) {
- nng_tls_dialer_close(ep->dialer);
+ nng_stream_dialer_close(ep->dialer);
}
if (ep->listener != NULL) {
- nng_tls_listener_close(ep->listener);
+ nng_stream_listener_close(ep->listener);
}
nni_mtx_unlock(&ep->mtx);
}
+// This parses off the optional source address that this transport uses.
+// The special handling of this URL format is quite honestly an historical
+// mistake, which we would remove if we could.
static int
-tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
+tlstran_url_parse_source(nni_url *url, nng_sockaddr *sa, const nni_url *surl)
{
- tlstran_ep * ep;
- int rv;
- uint16_t af;
- char * host;
- nng_sockaddr srcsa;
- nni_sock * sock = nni_dialer_sock(ndialer);
+ int af;
+ char * semi;
+ char * src;
+ size_t len;
+ int rv;
+ nni_aio *aio;
- if (strcmp(url->u_scheme, "tls+tcp") == 0) {
+ // We modify the URL. This relies on the fact that the underlying
+ // transport does not free this, so we can just use references.
+
+ url->u_scheme = surl->u_scheme;
+ url->u_port = surl->u_port;
+ url->u_hostname = surl->u_hostname;
+
+ if ((semi = strchr(url->u_hostname, ';')) == NULL) {
+ memset(sa, 0, sizeof(*sa));
+ return (0);
+ }
+
+ len = (size_t)(semi - url->u_hostname);
+ url->u_hostname = semi + 1;
+
+ if (strcmp(surl->u_scheme, "tls+tcp") == 0) {
af = NNG_AF_UNSPEC;
- } else if (strcmp(url->u_scheme, "tls+tcp4") == 0) {
+ } else if (strcmp(surl->u_scheme, "tls+tcp4") == 0) {
af = NNG_AF_INET;
- } else if (strcmp(url->u_scheme, "tls+tcp6") == 0) {
+ } else if (strcmp(surl->u_scheme, "tls+tcp6") == 0) {
af = NNG_AF_INET6;
} else {
return (NNG_EADDRINVAL);
}
+ if ((src = nni_alloc(len + 1)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ memcpy(src, surl->u_hostname, len);
+ src[len] = '\0';
+
+ if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
+ nni_free(src, len + 1);
+ return (rv);
+ }
+
+ nni_tcp_resolv(src, 0, af, 1, aio);
+ nni_aio_wait(aio);
+ if ((rv = nni_aio_result(aio)) == 0) {
+ nni_aio_get_sockaddr(aio, sa);
+ }
+ nni_aio_fini(aio);
+ nni_free(src, len + 1);
+ return (rv);
+}
+
+static int
+tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
+{
+ tlstran_ep * ep;
+ int rv;
+ nng_sockaddr srcsa;
+ nni_sock * sock = nni_dialer_sock(ndialer);
+ nni_url myurl;
+
// Check for invalid URL components.
if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) {
return (NNG_EADDRINVAL);
@@ -717,6 +730,11 @@ tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
(strlen(url->u_port) == 0)) {
return (NNG_EADDRINVAL);
}
+
+ if ((rv = tlstran_url_parse_source(&myurl, &srcsa, url)) != 0) {
+ return (NNG_EADDRINVAL);
+ }
+
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
return (NNG_ENOMEM);
}
@@ -726,56 +744,20 @@ tlstran_ep_init_dialer(void **dp, nni_url *url, nni_dialer *ndialer)
ep->authmode = NNG_TLS_AUTH_MODE_REQUIRED;
ep->url = url;
- ep->af = af;
ep->proto = nni_sock_proto_id(sock);
ep->ndialer = ndialer;
- // Detect an embedded local interface name in the hostname. This
- // syntax is only valid with dialers.
- if ((host = strchr(url->u_hostname, ';')) != NULL) {
- size_t len;
- char * src = NULL;
- nni_aio *aio;
- len = (uintptr_t) host - (uintptr_t) url->u_hostname;
- host++;
- if ((len < 2) || (strlen(host) == 0)) {
- tlstran_ep_fini(ep);
- return (NNG_EADDRINVAL);
- }
- if ((src = nni_alloc(len + 1)) == NULL) {
- tlstran_ep_fini(ep);
- return (NNG_ENOMEM);
- }
- memcpy(src, url->u_hostname, len);
- src[len] = 0;
-
- if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
- tlstran_ep_fini(ep);
- nni_strfree(src);
- return (rv);
- }
- nni_aio_set_input(aio, 0, &srcsa);
- nni_tcp_resolv(src, 0, af, 1, aio);
- nni_aio_wait(aio);
- rv = nni_aio_result(aio);
- nni_aio_fini(aio);
- nni_strfree(src);
- ep->host = host;
- } else {
- srcsa.s_family = NNG_AF_UNSPEC;
- ep->host = url->u_hostname;
- rv = 0;
+ if ((rv != 0) ||
+ ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) {
+ tlstran_ep_fini(ep);
+ return (rv);
}
-
- if ((rv != 0) || ((rv = nng_tls_dialer_alloc(&ep->dialer)) != 0) ||
- ((rv = nng_tls_dialer_setopt(ep->dialer, NNG_OPT_TLS_AUTH_MODE,
- &ep->authmode, sizeof(ep->authmode))) != 0) ||
- ((rv = nng_tls_dialer_setopt(ep->dialer, NNG_OPT_TLS_SERVER_NAME,
- ep->host, strlen(ep->host) + 1)) != 0)) {
+ if ((srcsa.s_family != NNG_AF_UNSPEC) &&
+ ((rv = nni_stream_dialer_setx(ep->dialer, NNG_OPT_LOCADDR, &srcsa,
+ sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) {
tlstran_ep_fini(ep);
return (rv);
}
-
*dp = ep;
return (0);
}
@@ -841,9 +823,11 @@ tlstran_ep_init_listener(void **lp, nni_url *url, nni_listener *nlistener)
rv = nni_aio_result(aio);
nni_aio_fini(aio);
- if ((rv != 0) || ((rv = nng_tls_listener_alloc(&ep->listener)) != 0) ||
- ((rv = nng_tls_listener_setopt(ep->listener, NNG_OPT_TLS_AUTH_MODE,
- &ep->authmode, sizeof(ep->authmode))) != 0)) {
+ if ((rv != 0) ||
+ ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0) ||
+ ((rv = nni_stream_listener_setx(ep->listener,
+ NNG_OPT_TLS_AUTH_MODE, &ep->authmode, sizeof(ep->authmode),
+ NNI_TYPE_INT32)) != 0)) {
tlstran_ep_fini(ep);
return (rv);
}
@@ -876,8 +860,7 @@ tlstran_ep_connect(void *arg, nni_aio *aio)
return;
}
p->useraio = aio;
- nni_aio_set_input(p->rslvaio, 0, &p->sa);
- nni_tcp_resolv(ep->host, ep->url->u_port, ep->af, 0, p->rslvaio);
+ nng_stream_dialer_dial(ep->dialer, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -888,7 +871,7 @@ tlstran_ep_bind(void *arg)
int rv;
nni_mtx_lock(&ep->mtx);
- rv = nng_tls_listener_listen(ep->listener, &ep->sa);
+ rv = nng_stream_listener_listen(ep->listener);
nni_mtx_unlock(&ep->mtx);
return (rv);
@@ -919,7 +902,7 @@ tlstran_ep_accept(void *arg, nni_aio *aio)
}
p->useraio = aio;
- nng_tls_listener_accept(ep->listener, p->connaio);
+ nng_stream_listener_accept(ep->listener, p->connaio);
nni_mtx_unlock(&ep->mtx);
}
@@ -929,8 +912,7 @@ tlstran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t)
tlstran_ep *ep = arg;
size_t val;
int rv;
- if (((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) &&
- (ep != NULL)) {
+ if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) {
nni_mtx_lock(&ep->mtx);
ep->rcvmax = val;
nni_mtx_unlock(&ep->mtx);
@@ -963,7 +945,7 @@ tlstran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t)
if (ep->dialer != NULL) {
return (nni_copyout_str(ep->url->u_rawurl, v, szp, t));
}
- rv = nni_tls_listener_getopt(
+ rv = nni_stream_listener_getx(
ep->listener, NNG_OPT_LOCADDR, &sa, &sz, NNI_TYPE_SOCKADDR);
if (rv != 0) {
return (rv);
@@ -990,12 +972,19 @@ tlstran_pipe_getopt(
tlstran_pipe *p = arg;
int rv;
- if ((rv = nni_tls_get(p->tls, name, buf, szp, t)) == NNG_ENOTSUP) {
+ if ((rv = nni_stream_getx(p->tls, name, buf, szp, t)) == NNG_ENOTSUP) {
rv = nni_getopt(tlstran_pipe_opts, name, p, buf, szp, t);
}
return (rv);
}
+static int
+tlstran_check_recvmaxsz(const void *v, size_t sz, nni_type t)
+{
+ size_t val;
+ return (nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t));
+}
+
static nni_tran_pipe_ops tlstran_pipe_ops = {
.p_init = tlstran_pipe_init,
.p_fini = tlstran_pipe_fini,
@@ -1023,6 +1012,16 @@ static nni_option tlstran_ep_options[] = {
},
};
+static nni_chkoption tlstran_checkopts[] = {
+ {
+ .o_name = NNG_OPT_RECVMAXSZ,
+ .o_check = tlstran_check_recvmaxsz,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
static int
tlstran_dialer_getopt(
void *arg, const char *name, void *buf, size_t *szp, nni_type t)
@@ -1030,7 +1029,7 @@ tlstran_dialer_getopt(
int rv;
tlstran_ep *ep = arg;
- rv = nni_tls_dialer_getopt(ep->dialer, name, buf, szp, t);
+ rv = nni_stream_dialer_getx(ep->dialer, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
rv = nni_getopt(tlstran_ep_options, name, ep, buf, szp, t);
}
@@ -1044,7 +1043,7 @@ tlstran_dialer_setopt(
int rv;
tlstran_ep *ep = arg;
- rv = nni_tls_dialer_setopt(
+ rv = nni_stream_dialer_setx(
ep != NULL ? ep->dialer : NULL, name, buf, sz, t);
if (rv == NNG_ENOTSUP) {
rv = nni_setopt(tlstran_ep_options, name, ep, buf, sz, t);
@@ -1059,7 +1058,7 @@ tlstran_listener_getopt(
int rv;
tlstran_ep *ep = arg;
- rv = nni_tls_listener_getopt(ep->listener, name, buf, szp, t);
+ rv = nni_stream_listener_getx(ep->listener, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
rv = nni_getopt(tlstran_ep_options, name, ep, buf, szp, t);
}
@@ -1073,7 +1072,7 @@ tlstran_listener_setopt(
int rv;
tlstran_ep *ep = arg;
- rv = nni_tls_listener_setopt(
+ rv = nni_stream_listener_setx(
ep != NULL ? ep->listener : NULL, name, buf, sz, t);
if (rv == NNG_ENOTSUP) {
rv = nni_setopt(tlstran_ep_options, name, ep, buf, sz, t);
@@ -1081,6 +1080,17 @@ tlstran_listener_setopt(
return (rv);
}
+static int
+tlstran_checkopt(const char *name, const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ rv = nni_chkopt(tlstran_checkopts, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("tls+tcp", name, buf, sz, t);
+ }
+ return (rv);
+}
+
static nni_tran_dialer_ops tlstran_dialer_ops = {
.d_init = tlstran_ep_init_dialer,
.d_fini = tlstran_ep_fini,
@@ -1108,6 +1118,7 @@ static nni_tran tls_tran = {
.tran_pipe = &tlstran_pipe_ops,
.tran_init = tlstran_init,
.tran_fini = tlstran_fini,
+ .tran_checkopt = tlstran_checkopt,
};
static nni_tran tls4_tran = {
@@ -1118,6 +1129,7 @@ static nni_tran tls4_tran = {
.tran_pipe = &tlstran_pipe_ops,
.tran_init = tlstran_init,
.tran_fini = tlstran_fini,
+ .tran_checkopt = tlstran_checkopt,
};
static nni_tran tls6_tran = {
@@ -1128,6 +1140,7 @@ static nni_tran tls6_tran = {
.tran_pipe = &tlstran_pipe_ops,
.tran_init = tlstran_init,
.tran_fini = tlstran_fini,
+ .tran_checkopt = tlstran_checkopt,
};
int
diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c
index bf10f7e0..3424480a 100644
--- a/src/transport/ws/websocket.c
+++ b/src/transport/ws/websocket.c
@@ -1,7 +1,7 @@
//
-// 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>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -26,56 +26,43 @@ typedef struct ws_dialer ws_dialer;
typedef struct ws_listener ws_listener;
typedef struct ws_pipe ws_pipe;
-typedef struct ws_hdr {
- nni_list_node node;
- char * name;
- char * value;
-} ws_hdr;
-
struct ws_dialer {
- uint16_t lproto; // local protocol
- uint16_t rproto; // remote protocol
- size_t rcvmax;
- char * prname;
- nni_list aios;
- nni_mtx mtx;
- nni_aio * connaio;
- nni_ws_dialer *dialer;
- nni_list headers; // req headers
- bool started;
- nni_dialer * ndialer;
+ uint16_t lproto; // local protocol
+ uint16_t rproto; // remote protocol
+ nni_list aios;
+ nni_mtx mtx;
+ nni_aio * connaio;
+ nng_stream_dialer *dialer;
+ bool started;
+ nni_dialer * ndialer;
};
struct ws_listener {
- uint16_t lproto; // local protocol
- uint16_t rproto; // remote protocol
- size_t rcvmax;
- char * prname;
- nni_list aios;
- nni_mtx mtx;
- nni_aio * accaio;
- nni_ws_listener *listener;
- nni_list headers; // res headers
- bool started;
- nni_listener * nlistener;
+ uint16_t lproto; // local protocol
+ uint16_t rproto; // remote protocol
+ nni_list aios;
+ nni_mtx mtx;
+ nni_aio * accaio;
+ nng_stream_listener *listener;
+ bool started;
+ nni_listener * nlistener;
};
struct ws_pipe {
- nni_mtx mtx;
- nni_pipe *npipe;
- size_t rcvmax;
- 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;
+ nni_mtx mtx;
+ nni_pipe * npipe;
+ bool closed;
+ uint16_t rproto;
+ uint16_t lproto;
+ nni_aio * user_txaio;
+ nni_aio * user_rxaio;
+ nni_aio * txaio;
+ nni_aio * rxaio;
+ nng_stream *ws;
};
static void
-ws_pipe_send_cb(void *arg)
+wstran_pipe_send_cb(void *arg)
{
ws_pipe *p = arg;
nni_aio *taio;
@@ -98,7 +85,7 @@ ws_pipe_send_cb(void *arg)
}
static void
-ws_pipe_recv_cb(void *arg)
+wstran_pipe_recv_cb(void *arg)
{
ws_pipe *p = arg;
nni_aio *raio = p->rxaio;
@@ -124,7 +111,7 @@ ws_pipe_recv_cb(void *arg)
}
static void
-ws_pipe_recv_cancel(nni_aio *aio, void *arg, int rv)
+wstran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv)
{
ws_pipe *p = arg;
nni_mtx_lock(&p->mtx);
@@ -139,7 +126,7 @@ ws_pipe_recv_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-ws_pipe_recv(void *arg, nni_aio *aio)
+wstran_pipe_recv(void *arg, nni_aio *aio)
{
ws_pipe *p = arg;
int rv;
@@ -148,18 +135,18 @@ ws_pipe_recv(void *arg, nni_aio *aio)
return;
}
nni_mtx_lock(&p->mtx);
- if ((rv = nni_aio_schedule(aio, ws_pipe_recv_cancel, p)) != 0) {
+ if ((rv = nni_aio_schedule(aio, wstran_pipe_recv_cancel, p)) != 0) {
nni_mtx_unlock(&p->mtx);
nni_aio_finish_error(aio, rv);
return;
}
p->user_rxaio = aio;
- nni_ws_recv_msg(p->ws, p->rxaio);
+ nng_stream_recv(p->ws, p->rxaio);
nni_mtx_unlock(&p->mtx);
}
static void
-ws_pipe_send_cancel(nni_aio *aio, void *arg, int rv)
+wstran_pipe_send_cancel(nni_aio *aio, void *arg, int rv)
{
ws_pipe *p = arg;
nni_mtx_lock(&p->mtx);
@@ -174,7 +161,7 @@ ws_pipe_send_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-ws_pipe_send(void *arg, nni_aio *aio)
+wstran_pipe_send(void *arg, nni_aio *aio)
{
ws_pipe *p = arg;
int rv;
@@ -183,7 +170,7 @@ ws_pipe_send(void *arg, nni_aio *aio)
return;
}
nni_mtx_lock(&p->mtx);
- if ((rv = nni_aio_schedule(aio, ws_pipe_send_cancel, p)) != 0) {
+ if ((rv = nni_aio_schedule(aio, wstran_pipe_send_cancel, p)) != 0) {
nni_mtx_unlock(&p->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -192,12 +179,12 @@ ws_pipe_send(void *arg, nni_aio *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);
+ nng_stream_send(p->ws, p->txaio);
nni_mtx_unlock(&p->mtx);
}
static void
-ws_pipe_stop(void *arg)
+wstran_pipe_stop(void *arg)
{
ws_pipe *p = arg;
@@ -206,7 +193,7 @@ ws_pipe_stop(void *arg)
}
static int
-ws_pipe_init(void *arg, nni_pipe *npipe)
+wstran_pipe_init(void *arg, nni_pipe *npipe)
{
ws_pipe *p = arg;
p->npipe = npipe;
@@ -214,22 +201,20 @@ ws_pipe_init(void *arg, nni_pipe *npipe)
}
static void
-ws_pipe_fini(void *arg)
+wstran_pipe_fini(void *arg)
{
ws_pipe *p = arg;
nni_aio_fini(p->rxaio);
nni_aio_fini(p->txaio);
- if (p->ws) {
- nni_ws_fini(p->ws);
- }
+ nng_stream_free(p->ws);
nni_mtx_fini(&p->mtx);
NNI_FREE_STRUCT(p);
}
static void
-ws_pipe_close(void *arg)
+wstran_pipe_close(void *arg)
{
ws_pipe *p = arg;
@@ -237,12 +222,12 @@ ws_pipe_close(void *arg)
nni_aio_close(p->txaio);
nni_mtx_lock(&p->mtx);
- nni_ws_close(p->ws);
+ nng_stream_close(p->ws);
nni_mtx_unlock(&p->mtx);
}
static int
-ws_pipe_alloc(ws_pipe **pipep, void *ws)
+wstran_pipe_alloc(ws_pipe **pipep, void *ws)
{
ws_pipe *p;
int rv;
@@ -253,9 +238,9 @@ ws_pipe_alloc(ws_pipe **pipep, void *ws)
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);
+ if (((rv = nni_aio_init(&p->txaio, wstran_pipe_send_cb, p)) != 0) ||
+ ((rv = nni_aio_init(&p->rxaio, wstran_pipe_recv_cb, p)) != 0)) {
+ wstran_pipe_fini(p);
return (rv);
}
p->ws = ws;
@@ -265,46 +250,20 @@ ws_pipe_alloc(ws_pipe **pipep, void *ws)
}
static uint16_t
-ws_pipe_peer(void *arg)
+wstran_pipe_peer(void *arg)
{
ws_pipe *p = arg;
return (p->rproto);
}
-// We have very different approaches for server and client.
-// Servers use the HTTP server framework, and a request methodology.
-
-static int
-ws_hook(void *arg, nni_http_req *req, nni_http_res *res)
-{
- ws_listener *l = arg;
- ws_hdr * h;
- NNI_ARG_UNUSED(req);
-
- // Eventually we'll want user customizable hooks.
- // For now we just set the headers we want.
-
- NNI_LIST_FOREACH (&l->headers, h) {
- int rv;
- rv = nng_http_res_set_header(res, h->name, h->value);
- if (rv != 0) {
- return (rv);
- }
- }
- return (0);
-}
-
static int
ws_listener_bind(void *arg)
{
ws_listener *l = arg;
int rv;
- nni_ws_listener_set_maxframe(l->listener, l->rcvmax);
- nni_ws_listener_hook(l->listener, ws_hook, l);
-
- if ((rv = nni_ws_listener_listen(l->listener)) == 0) {
+ if ((rv = nng_stream_listener_listen(l->listener)) == 0) {
l->started = true;
}
return (rv);
@@ -324,7 +283,7 @@ ws_listener_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-ws_listener_accept(void *arg, nni_aio *aio)
+wstran_listener_accept(void *arg, nni_aio *aio)
{
ws_listener *l = arg;
int rv;
@@ -343,13 +302,13 @@ ws_listener_accept(void *arg, nni_aio *aio)
}
nni_list_append(&l->aios, aio);
if (aio == nni_list_first(&l->aios)) {
- nni_ws_listener_accept(l->listener, l->accaio);
+ nng_stream_listener_accept(l->listener, l->accaio);
}
nni_mtx_unlock(&l->mtx);
}
static void
-ws_dialer_cancel(nni_aio *aio, void *arg, int rv)
+wstran_dialer_cancel(nni_aio *aio, void *arg, int rv)
{
ws_dialer *d = arg;
@@ -362,7 +321,7 @@ ws_dialer_cancel(nni_aio *aio, void *arg, int rv)
}
static void
-ws_dialer_connect(void *arg, nni_aio *aio)
+wstran_dialer_connect(void *arg, nni_aio *aio)
{
ws_dialer *d = arg;
int rv;
@@ -370,20 +329,9 @@ ws_dialer_connect(void *arg, nni_aio *aio)
if (nni_aio_begin(aio) != 0) {
return;
}
- if (!d->started) {
- ws_hdr *h;
- NNI_LIST_FOREACH (&d->headers, h) {
- int rv =
- nni_ws_dialer_header(d->dialer, h->name, h->value);
- if (rv != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
- }
- }
nni_mtx_lock(&d->mtx);
- if ((rv = nni_aio_schedule(aio, ws_dialer_cancel, d)) != 0) {
+ if ((rv = nni_aio_schedule(aio, wstran_dialer_cancel, d)) != 0) {
nni_mtx_unlock(&d->mtx);
nni_aio_finish_error(aio, rv);
return;
@@ -391,225 +339,11 @@ ws_dialer_connect(void *arg, nni_aio *aio)
NNI_ASSERT(nni_list_empty(&d->aios));
d->started = true;
nni_list_append(&d->aios, aio);
- nni_ws_dialer_set_maxframe(d->dialer, d->rcvmax);
- nni_ws_dialer_dial(d->dialer, d->connaio);
- nni_mtx_unlock(&d->mtx);
-}
-
-static int
-ws_check_string(const void *v, size_t sz, nni_opt_type t)
-{
- if ((t != NNI_TYPE_OPAQUE) && (t != NNI_TYPE_STRING)) {
- return (NNG_EBADTYPE);
- }
- if (nni_strnlen(v, sz) >= sz) {
- return (NNG_EINVAL);
- }
- return (0);
-}
-
-static int
-ws_dialer_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_dialer *d = arg;
- size_t val;
- int rv;
-
- if (((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) &&
- (d != NULL)) {
- nni_mtx_lock(&d->mtx);
- d->rcvmax = val;
- nni_mtx_unlock(&d->mtx);
- nni_ws_dialer_set_maxframe(d->dialer, val);
- }
- return (rv);
-}
-
-static int
-ws_dialer_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_dialer *d = arg;
- int rv;
- nni_mtx_lock(&d->mtx);
- rv = nni_copyout_size(d->rcvmax, v, szp, t);
+ nng_stream_dialer_dial(d->dialer, d->connaio);
nni_mtx_unlock(&d->mtx);
- return (rv);
-}
-
-static int
-ws_listener_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_listener *l = arg;
- size_t val;
- int rv;
-
- if (((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) &&
- (l != NULL)) {
- nni_mtx_lock(&l->mtx);
- l->rcvmax = val;
- nni_mtx_unlock(&l->mtx);
- nni_ws_listener_set_maxframe(l->listener, val);
- }
- return (rv);
-}
-
-static int
-ws_listener_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_listener *l = arg;
- int rv;
- nni_mtx_lock(&l->mtx);
- rv = nni_copyout_size(l->rcvmax, v, szp, t);
- nni_mtx_unlock(&l->mtx);
- return (rv);
-}
-
-static int
-ws_set_headers(nni_list *headers, const char *v)
-{
- char * dupstr;
- size_t duplen;
- char * name;
- char * value;
- char * nl;
- nni_list l;
- ws_hdr * h;
- int rv;
-
- NNI_LIST_INIT(&l, ws_hdr, node);
- if ((dupstr = nni_strdup(v)) == NULL) {
- return (NNG_ENOMEM);
- }
- duplen = strlen(dupstr) + 1; // so we can free it later
- name = dupstr;
- for (;;) {
- if ((value = strchr(name, ':')) == NULL) {
- // Note that this also means that if
- // a bare word is present, we ignore it.
- break;
- }
- *value = '\0';
- value++;
- while (*value == ' ') {
- // Skip leading whitespace. Not strictly
- // necessary, but still a good idea.
- value++;
- }
- nl = value;
- // Find the end of the line -- should be CRLF, but can
- // also be unterminated or just LF if user
- while ((*nl != '\0') && (*nl != '\r') && (*nl != '\n')) {
- nl++;
- }
- while ((*nl == '\r') || (*nl == '\n')) {
- *nl = '\0';
- nl++;
- }
-
- if ((h = NNI_ALLOC_STRUCT(h)) == NULL) {
- rv = NNG_ENOMEM;
- goto done;
- }
- nni_list_append(&l, h);
- if (((h->name = nni_strdup(name)) == NULL) ||
- ((h->value = nni_strdup(value)) == NULL)) {
- rv = NNG_ENOMEM;
- goto done;
- }
-
- name = nl;
- }
-
- while ((h = nni_list_first(headers)) != NULL) {
- nni_list_remove(headers, h);
- nni_strfree(h->name);
- nni_strfree(h->value);
- NNI_FREE_STRUCT(h);
- }
- while ((h = nni_list_first(&l)) != NULL) {
- nni_list_remove(&l, h);
- nni_list_append(headers, h);
- }
- rv = 0;
-
-done:
- while ((h = nni_list_first(&l)) != NULL) {
- nni_list_remove(&l, h);
- nni_strfree(h->name);
- nni_strfree(h->value);
- NNI_FREE_STRUCT(h);
- }
- nni_free(dupstr, duplen);
- return (rv);
-}
-
-static int
-ws_dialer_set_reqhdrs(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_dialer *d = arg;
- int rv;
-
- if (((rv = ws_check_string(v, sz, t)) == 0) && (d != NULL)) {
- if (d->started) {
- return (NNG_EBUSY);
- }
- nni_mtx_lock(&d->mtx);
- rv = ws_set_headers(&d->headers, v);
- nni_mtx_unlock(&d->mtx);
- }
- return (rv);
-}
-
-static int
-ws_listener_set_reshdrs(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_listener *l = arg;
- int rv;
-
- if (((rv = ws_check_string(v, sz, t)) == 0) && (l != NULL)) {
- if (l->started) {
- return (NNG_EBUSY);
- }
- nni_mtx_lock(&l->mtx);
- rv = ws_set_headers(&l->headers, v);
- nni_mtx_unlock(&l->mtx);
- }
- return (rv);
-}
-
-static int
-ws_pipe_get_reshdrs(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_pipe * p = arg;
- const char *s;
-
- if ((s = nni_ws_response_headers(p->ws)) == NULL) {
- return (NNG_ENOMEM);
- }
- return (nni_copyout_str(s, v, szp, t));
-}
-
-static int
-ws_pipe_get_reqhdrs(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_pipe * p = arg;
- const char *s;
-
- if ((s = nni_ws_request_headers(p->ws)) == NULL) {
- return (NNG_ENOMEM);
- }
- return (nni_copyout_str(s, v, szp, t));
}
static const nni_option ws_pipe_options[] = {
- {
- .o_name = NNG_OPT_WS_REQUEST_HEADERS,
- .o_get = ws_pipe_get_reqhdrs,
- },
- {
- .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
- .o_get = ws_pipe_get_reshdrs,
- },
// terminate list
{
.o_name = NULL,
@@ -617,113 +351,62 @@ static const nni_option ws_pipe_options[] = {
};
static int
-ws_pipe_getopt(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
+wstran_pipe_getopt(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
ws_pipe *p = arg;
int rv;
- if ((rv = nni_ws_getopt(p->ws, name, buf, szp, t)) == NNG_ENOTSUP) {
+ if ((rv = nni_stream_getx(p->ws, name, buf, szp, t)) == NNG_ENOTSUP) {
rv = nni_getopt(ws_pipe_options, name, p, buf, szp, t);
}
return (rv);
}
static nni_tran_pipe_ops ws_pipe_ops = {
- .p_init = ws_pipe_init,
- .p_fini = ws_pipe_fini,
- .p_stop = ws_pipe_stop,
- .p_send = ws_pipe_send,
- .p_recv = ws_pipe_recv,
- .p_close = ws_pipe_close,
- .p_peer = ws_pipe_peer,
- .p_getopt = ws_pipe_getopt,
-};
-
-static nni_option ws_dialer_options[] = {
- {
- .o_name = NNG_OPT_RECVMAXSZ,
- .o_get = ws_dialer_get_recvmaxsz,
- .o_set = ws_dialer_set_recvmaxsz,
- },
- {
- .o_name = NNG_OPT_WS_REQUEST_HEADERS,
- .o_set = ws_dialer_set_reqhdrs,
- },
- // terminate list
- {
- .o_name = NULL,
- },
-};
-
-static nni_option ws_listener_options[] = {
- {
- .o_name = NNG_OPT_RECVMAXSZ,
- .o_get = ws_listener_get_recvmaxsz,
- .o_set = ws_listener_set_recvmaxsz,
- },
- {
- .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
- .o_set = ws_listener_set_reshdrs,
- },
- // terminate list
- {
- .o_name = NULL,
- },
+ .p_init = wstran_pipe_init,
+ .p_fini = wstran_pipe_fini,
+ .p_stop = wstran_pipe_stop,
+ .p_send = wstran_pipe_send,
+ .p_recv = wstran_pipe_recv,
+ .p_close = wstran_pipe_close,
+ .p_peer = wstran_pipe_peer,
+ .p_getopt = wstran_pipe_getopt,
};
static void
-ws_dialer_fini(void *arg)
+wstran_dialer_fini(void *arg)
{
ws_dialer *d = arg;
- ws_hdr * hdr;
nni_aio_stop(d->connaio);
- if (d->dialer != NULL) {
- nni_ws_dialer_fini(d->dialer);
- }
+ nng_stream_dialer_free(d->dialer);
nni_aio_fini(d->connaio);
- while ((hdr = nni_list_first(&d->headers)) != NULL) {
- nni_list_remove(&d->headers, hdr);
- nni_strfree(hdr->name);
- nni_strfree(hdr->value);
- NNI_FREE_STRUCT(hdr);
- }
- nni_strfree(d->prname);
nni_mtx_fini(&d->mtx);
NNI_FREE_STRUCT(d);
}
static void
-ws_listener_fini(void *arg)
+wstran_listener_fini(void *arg)
{
ws_listener *l = arg;
- ws_hdr * hdr;
nni_aio_stop(l->accaio);
- if (l->listener != NULL) {
- nni_ws_listener_fini(l->listener);
- }
+ nng_stream_listener_free(l->listener);
nni_aio_fini(l->accaio);
- while ((hdr = nni_list_first(&l->headers)) != NULL) {
- nni_list_remove(&l->headers, hdr);
- nni_strfree(hdr->name);
- nni_strfree(hdr->value);
- NNI_FREE_STRUCT(hdr);
- }
- nni_strfree(l->prname);
nni_mtx_fini(&l->mtx);
NNI_FREE_STRUCT(l);
}
static void
-ws_connect_cb(void *arg)
+wstran_connect_cb(void *arg)
{
- ws_dialer *d = arg;
- ws_pipe * p;
- nni_aio * caio = d->connaio;
- nni_aio * uaio;
- int rv;
- nni_ws * ws = NULL;
+ ws_dialer * d = arg;
+ ws_pipe * p;
+ nni_aio * caio = d->connaio;
+ nni_aio * uaio;
+ int rv;
+ nng_stream *ws = NULL;
nni_mtx_lock(&d->mtx);
if (nni_aio_result(caio) == 0) {
@@ -731,9 +414,7 @@ ws_connect_cb(void *arg)
}
if ((uaio = nni_list_first(&d->aios)) == NULL) {
// The client stopped caring about this!
- if (ws != NULL) {
- nni_ws_fini(ws);
- }
+ nng_stream_free(ws);
nni_mtx_unlock(&d->mtx);
return;
}
@@ -741,11 +422,10 @@ ws_connect_cb(void *arg)
NNI_ASSERT(nni_list_empty(&d->aios));
if ((rv = nni_aio_result(caio)) != 0) {
nni_aio_finish_error(uaio, rv);
- } else if ((rv = ws_pipe_alloc(&p, ws)) != 0) {
- nni_ws_fini(ws);
+ } else if ((rv = wstran_pipe_alloc(&p, ws)) != 0) {
+ nng_stream_free(ws);
nni_aio_finish_error(uaio, rv);
} else {
- p->rcvmax = d->rcvmax;
p->rproto = d->rproto;
p->lproto = d->lproto;
@@ -756,25 +436,25 @@ ws_connect_cb(void *arg)
}
static void
-ws_dialer_close(void *arg)
+wstran_dialer_close(void *arg)
{
ws_dialer *d = arg;
nni_aio_close(d->connaio);
- nni_ws_dialer_close(d->dialer);
+ nng_stream_dialer_close(d->dialer);
}
static void
-ws_listener_close(void *arg)
+wstran_listener_close(void *arg)
{
ws_listener *l = arg;
nni_aio_close(l->accaio);
- nni_ws_listener_close(l->listener);
+ nng_stream_listener_close(l->listener);
}
static void
-ws_accept_cb(void *arg)
+wstran_accept_cb(void *arg)
{
ws_listener *l = arg;
nni_aio * aaio = l->accaio;
@@ -789,16 +469,15 @@ ws_accept_cb(void *arg)
nni_aio_finish_error(uaio, rv);
}
} else {
- nni_ws *ws = nni_aio_get_output(aaio, 0);
+ nng_stream *ws = nni_aio_get_output(aaio, 0);
if (uaio != NULL) {
ws_pipe *p;
// Make a pipe
nni_aio_list_remove(uaio);
- if ((rv = ws_pipe_alloc(&p, ws)) != 0) {
- nni_ws_close(ws);
+ if ((rv = wstran_pipe_alloc(&p, ws)) != 0) {
+ nng_stream_close(ws);
nni_aio_finish_error(uaio, rv);
} else {
- p->rcvmax = l->rcvmax;
p->rproto = l->rproto;
p->lproto = l->lproto;
@@ -808,37 +487,40 @@ ws_accept_cb(void *arg)
}
}
if (!nni_list_empty(&l->aios)) {
- nni_ws_listener_accept(l->listener, aaio);
+ nng_stream_listener_accept(l->listener, aaio);
}
nni_mtx_unlock(&l->mtx);
}
static int
-ws_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
+wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer)
{
- ws_dialer * d;
- nni_sock * s = nni_dialer_sock(ndialer);
- const char *n;
- int rv;
+ ws_dialer *d;
+ nni_sock * s = nni_dialer_sock(ndialer);
+ int rv;
+ char prname[64];
if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
return (NNG_ENOMEM);
}
nni_mtx_init(&d->mtx);
- NNI_LIST_INIT(&d->headers, ws_hdr, node);
nni_aio_list_init(&d->aios);
d->lproto = nni_sock_proto_id(s);
d->rproto = nni_sock_peer_id(s);
d->ndialer = ndialer;
- n = nni_sock_peer_name(s);
- if (((rv = nni_ws_dialer_init(&d->dialer, url)) != 0) ||
- ((rv = nni_aio_init(&d->connaio, ws_connect_cb, d)) != 0) ||
- ((rv = nni_asprintf(&d->prname, "%s.sp.nanomsg.org", n)) != 0) ||
- ((rv = nni_ws_dialer_proto(d->dialer, d->prname)) != 0)) {
- ws_dialer_fini(d);
+ snprintf(prname, sizeof(prname), "%s.sp.nanomsg.org",
+ nni_sock_peer_name(s));
+
+ if (((rv = nni_ws_dialer_alloc(&d->dialer, url)) != 0) ||
+ ((rv = nni_aio_init(&d->connaio, wstran_connect_cb, d)) != 0) ||
+ ((rv = nng_stream_dialer_set_bool(
+ d->dialer, NNI_OPT_WS_MSGMODE, true)) != 0) ||
+ ((rv = nng_stream_dialer_set_string(
+ d->dialer, NNG_OPT_WS_PROTOCOL, prname)) != 0)) {
+ wstran_dialer_fini(d);
return (rv);
}
@@ -847,31 +529,34 @@ ws_dialer_init(void **dp, nni_url *url, nni_dialer *ndialer)
}
static int
-ws_listener_init(void **lp, nni_url *url, nni_listener *nlistener)
+wstran_listener_init(void **lp, nng_url *url, nni_listener *nlistener)
{
ws_listener *l;
- const char * n;
int rv;
- nni_sock * sock = nni_listener_sock(nlistener);
+ nni_sock * s = nni_listener_sock(nlistener);
+ char prname[64];
if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
return (NNG_ENOMEM);
}
nni_mtx_init(&l->mtx);
- NNI_LIST_INIT(&l->headers, ws_hdr, node);
nni_aio_list_init(&l->aios);
- l->lproto = nni_sock_proto_id(sock);
- l->rproto = nni_sock_peer_id(sock);
- n = nni_sock_proto_name(sock);
+ l->lproto = nni_sock_proto_id(s);
+ l->rproto = nni_sock_peer_id(s);
l->nlistener = nlistener;
- if (((rv = nni_ws_listener_init(&l->listener, url)) != 0) ||
- ((rv = nni_aio_init(&l->accaio, ws_accept_cb, l)) != 0) ||
- ((rv = nni_asprintf(&l->prname, "%s.sp.nanomsg.org", n)) != 0) ||
- ((rv = nni_ws_listener_proto(l->listener, l->prname)) != 0)) {
- ws_listener_fini(l);
+ snprintf(prname, sizeof(prname), "%s.sp.nanomsg.org",
+ nni_sock_proto_name(s));
+
+ if (((rv = nni_ws_listener_alloc(&l->listener, url)) != 0) ||
+ ((rv = nni_aio_init(&l->accaio, wstran_accept_cb, l)) != 0) ||
+ ((rv = nng_stream_listener_set_bool(
+ l->listener, NNI_OPT_WS_MSGMODE, true)) != 0) ||
+ ((rv = nng_stream_listener_set_string(
+ l->listener, NNG_OPT_WS_PROTOCOL, prname)) != 0)) {
+ wstran_listener_fini(l);
return (rv);
}
*lp = l;
@@ -879,350 +564,143 @@ ws_listener_init(void **lp, nni_url *url, nni_listener *nlistener)
}
static int
-ws_tran_init(void)
+wstran_init(void)
{
return (0);
}
static void
-ws_tran_fini(void)
+wstran_fini(void)
{
}
-static nni_tran_dialer_ops ws_dialer_ops = {
- .d_init = ws_dialer_init,
- .d_fini = ws_dialer_fini,
- .d_connect = ws_dialer_connect,
- .d_close = ws_dialer_close,
- .d_options = ws_dialer_options,
-};
-
-static nni_tran_listener_ops ws_listener_ops = {
- .l_init = ws_listener_init,
- .l_fini = ws_listener_fini,
- .l_bind = ws_listener_bind,
- .l_accept = ws_listener_accept,
- .l_close = ws_listener_close,
- .l_options = ws_listener_options,
-};
-
-static nni_tran ws_tran = {
- .tran_version = NNI_TRANSPORT_VERSION,
- .tran_scheme = "ws",
- .tran_dialer = &ws_dialer_ops,
- .tran_listener = &ws_listener_ops,
- .tran_pipe = &ws_pipe_ops,
- .tran_init = ws_tran_init,
- .tran_fini = ws_tran_fini,
+static const nni_option wstran_ep_opts[] = {
+ // terminate list
+ {
+ .o_name = NULL,
+ },
};
-int
-nng_ws_register(void)
-{
- return (nni_tran_register(&ws_tran));
-}
-
-#ifdef NNG_TRANSPORT_WSS
-
-static int
-wss_dialer_get_tlsconfig(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_dialer * d = arg;
- nng_tls_config *tls;
- int rv;
-
- if (((rv = nni_ws_dialer_get_tls(d->dialer, &tls)) != 0) ||
- ((rv = nni_copyout_ptr(tls, v, szp, t)) != 0)) {
- return (rv);
- }
- return (0);
-}
-
-static int
-wss_listener_get_tlsconfig(void *arg, void *v, size_t *szp, nni_opt_type t)
-{
- ws_listener * l = arg;
- nng_tls_config *tls;
- int rv;
-
- if (((rv = nni_ws_listener_get_tls(l->listener, &tls)) != 0) ||
- ((rv = nni_copyout_ptr(tls, v, szp, t)) != 0)) {
- return (rv);
- }
- return (0);
-}
-
-static int
-wss_dialer_set_tlsconfig(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_dialer * d = arg;
- nng_tls_config *cfg;
- int rv;
-
- if ((rv = nni_copyin_ptr((void **) &cfg, v, sz, t)) != 0) {
- return (rv);
- }
- if (cfg == NULL) {
- return (NNG_EINVAL);
- }
- if (d != NULL) {
- rv = nni_ws_dialer_set_tls(d->dialer, cfg);
- }
- return (rv);
-}
-
static int
-wss_listener_set_tlsconfig(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_listener * l = arg;
- nng_tls_config *cfg;
- int rv;
-
- if ((rv = nni_copyin_ptr((void **) &cfg, v, sz, t)) != 0) {
- return (rv);
- }
- if (cfg == NULL) {
- return (NNG_EINVAL);
- }
- if (l != NULL) {
- rv = nni_ws_listener_set_tls(l->listener, cfg);
- }
- return (rv);
-}
-
-static int
-wss_dialer_set_cert_key_file(
- void *arg, const void *v, size_t sz, nni_opt_type t)
+wstran_dialer_getopt(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
ws_dialer *d = arg;
int rv;
- if (((rv = ws_check_string(v, sz, t)) == 0) && (d != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_dialer_get_tls(d->dialer, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_cert_key_file(tls, v, NULL);
- nni_tls_config_fini(tls);
+ rv = nni_stream_dialer_getx(d->dialer, name, buf, szp, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_getopt(wstran_ep_opts, name, d, buf, szp, t);
}
return (rv);
}
static int
-wss_listener_set_cert_key_file(
- void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_listener *l = arg;
- int rv;
-
- if (((rv = ws_check_string(v, sz, t)) == 0) && (l != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_listener_get_tls(l->listener, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_cert_key_file(tls, v, NULL);
- nni_tls_config_fini(tls);
- }
- return (rv);
-}
-
-static int
-wss_dialer_set_ca_file(void *arg, const void *v, size_t sz, nni_opt_type t)
+wstran_dialer_setopt(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
ws_dialer *d = arg;
int rv;
- if (((rv = ws_check_string(v, sz, t)) == 0) && (d != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_dialer_get_tls(d->dialer, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_ca_file(tls, v);
- nni_tls_config_fini(tls);
+ rv = nni_stream_dialer_setx(d->dialer, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_setopt(wstran_ep_opts, name, d, buf, sz, t);
}
return (rv);
}
static int
-wss_listener_set_ca_file(void *arg, const void *v, size_t sz, nni_opt_type t)
+wstran_listener_getopt(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
ws_listener *l = arg;
int rv;
- if (((rv = ws_check_string(v, sz, t)) == 0) && (l != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_listener_get_tls(l->listener, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_ca_file(tls, v);
- nni_tls_config_fini(tls);
- }
- return (rv);
-}
-
-static int
-wss_dialer_set_auth_mode(void *arg, const void *v, size_t sz, nni_opt_type t)
-{
- ws_dialer *d = arg;
- int rv;
- int mode;
-
- rv = nni_copyin_int(&mode, v, sz, NNG_TLS_AUTH_MODE_NONE,
- NNG_TLS_AUTH_MODE_REQUIRED, t);
-
- if ((rv == 0) && (d != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_dialer_get_tls(d->dialer, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_auth_mode(tls, mode);
- nni_tls_config_fini(tls);
+ rv = nni_stream_listener_getx(l->listener, name, buf, szp, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_getopt(wstran_ep_opts, name, l, buf, szp, t);
}
return (rv);
}
static int
-wss_listener_set_auth_mode(void *arg, const void *v, size_t sz, nni_opt_type t)
+wstran_listener_setopt(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
ws_listener *l = arg;
int rv;
- int mode;
-
- rv = nni_copyin_int(&mode, v, sz, NNG_TLS_AUTH_MODE_NONE,
- NNG_TLS_AUTH_MODE_REQUIRED, t);
- if ((rv == 0) && (l != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_listener_get_tls(l->listener, &tls)) != 0) {
- return (rv);
- }
- rv = nng_tls_config_auth_mode(tls, mode);
- nni_tls_config_fini(tls);
+ rv = nni_stream_listener_setx(l->listener, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_setopt(wstran_ep_opts, name, l, buf, sz, t);
}
return (rv);
}
+static nni_chkoption wstran_checkopts[] = {
+ {
+ .o_name = NULL,
+ },
+};
+
static int
-wss_dialer_set_tls_server_name(
- void *arg, const void *v, size_t sz, nni_opt_type t)
+wstran_checkopt(const char *name, const void *buf, size_t sz, nni_type t)
{
- ws_dialer *d = arg;
- int rv;
-
- if (((rv = ws_check_string(v, sz, t)) == 0) && (d != NULL)) {
- nng_tls_config *tls;
-
- if ((rv = nni_ws_dialer_get_tls(d->dialer, &tls)) != 0) {
- return (rv);
- }
-
- rv = nng_tls_config_server_name(tls, v);
- nni_tls_config_fini(tls);
+ int rv;
+ rv = nni_chkopt(wstran_checkopts, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("ws", name, buf, sz, t);
}
return (rv);
}
-static nni_option wss_dialer_options[] = {
- {
- .o_name = NNG_OPT_RECVMAXSZ,
- .o_get = ws_dialer_get_recvmaxsz,
- .o_set = ws_dialer_set_recvmaxsz,
- },
- {
- .o_name = NNG_OPT_WS_REQUEST_HEADERS,
- .o_set = ws_dialer_set_reqhdrs,
- },
- {
- .o_name = NNG_OPT_TLS_CONFIG,
- .o_get = wss_dialer_get_tlsconfig,
- .o_set = wss_dialer_set_tlsconfig,
- },
- {
- .o_name = NNG_OPT_TLS_CERT_KEY_FILE,
- .o_set = wss_dialer_set_cert_key_file,
- },
- {
- .o_name = NNG_OPT_TLS_CA_FILE,
- .o_set = wss_dialer_set_ca_file,
- },
- {
- .o_name = NNG_OPT_TLS_AUTH_MODE,
- .o_set = wss_dialer_set_auth_mode,
- },
- {
- .o_name = NNG_OPT_TLS_SERVER_NAME,
- .o_set = wss_dialer_set_tls_server_name,
- },
- // terminate list
- {
- .o_name = NULL,
- },
+static nni_tran_dialer_ops ws_dialer_ops = {
+ .d_init = wstran_dialer_init,
+ .d_fini = wstran_dialer_fini,
+ .d_connect = wstran_dialer_connect,
+ .d_close = wstran_dialer_close,
+ .d_setopt = wstran_dialer_setopt,
+ .d_getopt = wstran_dialer_getopt,
};
-static nni_option wss_listener_options[] = {
- {
- .o_name = NNG_OPT_RECVMAXSZ,
- .o_get = ws_listener_get_recvmaxsz,
- .o_set = ws_listener_set_recvmaxsz,
- },
- {
- .o_name = NNG_OPT_WS_RESPONSE_HEADERS,
- .o_set = ws_listener_set_reshdrs,
- },
- {
- .o_name = NNG_OPT_TLS_CONFIG,
- .o_get = wss_listener_get_tlsconfig,
- .o_set = wss_listener_set_tlsconfig,
- },
- {
- .o_name = NNG_OPT_TLS_CERT_KEY_FILE,
- .o_set = wss_listener_set_cert_key_file,
- },
- {
- .o_name = NNG_OPT_TLS_CA_FILE,
- .o_set = wss_listener_set_ca_file,
- },
- {
- .o_name = NNG_OPT_TLS_AUTH_MODE,
- .o_set = wss_listener_set_auth_mode,
- },
- // terminate list
- {
- .o_name = NULL,
- },
+static nni_tran_listener_ops ws_listener_ops = {
+ .l_init = wstran_listener_init,
+ .l_fini = wstran_listener_fini,
+ .l_bind = ws_listener_bind,
+ .l_accept = wstran_listener_accept,
+ .l_close = wstran_listener_close,
+ .l_setopt = wstran_listener_setopt,
+ .l_getopt = wstran_listener_getopt,
};
-static nni_tran_dialer_ops wss_dialer_ops = {
- .d_init = ws_dialer_init,
- .d_fini = ws_dialer_fini,
- .d_connect = ws_dialer_connect,
- .d_close = ws_dialer_close,
- .d_options = wss_dialer_options,
+static nni_tran ws_tran = {
+ .tran_version = NNI_TRANSPORT_VERSION,
+ .tran_scheme = "ws",
+ .tran_dialer = &ws_dialer_ops,
+ .tran_listener = &ws_listener_ops,
+ .tran_pipe = &ws_pipe_ops,
+ .tran_init = wstran_init,
+ .tran_fini = wstran_fini,
+ .tran_checkopt = wstran_checkopt,
};
-static nni_tran_listener_ops wss_listener_ops = {
- .l_init = ws_listener_init,
- .l_fini = ws_listener_fini,
- .l_bind = ws_listener_bind,
- .l_accept = ws_listener_accept,
- .l_close = ws_listener_close,
- .l_options = wss_listener_options,
-};
+int
+nng_ws_register(void)
+{
+ return (nni_tran_register(&ws_tran));
+}
+
+#ifdef NNG_TRANSPORT_WSS
static nni_tran wss_tran = {
.tran_version = NNI_TRANSPORT_VERSION,
.tran_scheme = "wss",
- .tran_dialer = &wss_dialer_ops,
- .tran_listener = &wss_listener_ops,
+ .tran_dialer = &ws_dialer_ops,
+ .tran_listener = &ws_listener_ops,
.tran_pipe = &ws_pipe_ops,
- .tran_init = ws_tran_init,
- .tran_fini = ws_tran_fini,
+ .tran_init = wstran_init,
+ .tran_fini = wstran_fini,
+ .tran_checkopt = wstran_checkopt,
};
int