aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2019-01-21 22:40:10 -0800
committerGarrett D'Amore <garrett@damore.org>2019-02-16 19:22:27 -0800
commit5cf750697624d4fd63cfe26921209d7c30e1a2d2 (patch)
treebf11695e5f1ec5e400c87da0cc6ff23935a2eeff
parentca655b9db689ee0e655248b1a9f166b8db6cc984 (diff)
downloadnng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.tar.gz
nng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.tar.bz2
nng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.zip
fixes #872 create unified nng_stream API
This is a major change, and includes changes to use a polymorphic stream API for all transports. There have been related bugs fixed along the way. Additionally the man pages have changed. The old non-polymorphic APIs are removed now. This is a breaking change, but the old APIs were never part of any released public API.
-rw-r--r--docs/man/CMakeLists.txt106
-rw-r--r--docs/man/libnng.3.adoc560
-rw-r--r--docs/man/man3ipc.desc5
-rw-r--r--docs/man/man3str.desc7
-rw-r--r--docs/man/man3str.sect (renamed from docs/man/man3ipc.sect)0
-rw-r--r--docs/man/nng_getopt.3.adoc12
-rw-r--r--docs/man/nng_ipc.5.adoc87
-rw-r--r--docs/man/nng_ipc_close.3ipc.adoc61
-rw-r--r--docs/man/nng_ipc_dialer.5.adoc51
-rw-r--r--docs/man/nng_ipc_dialer_alloc.3ipc.adoc49
-rw-r--r--docs/man/nng_ipc_dialer_close.3ipc.adoc57
-rw-r--r--docs/man/nng_ipc_dialer_dial.3ipc.adoc65
-rw-r--r--docs/man/nng_ipc_dialer_getopt.3ipc.adoc64
-rw-r--r--docs/man/nng_ipc_dialer_setopt.3ipc.adoc59
-rw-r--r--docs/man/nng_ipc_free.3ipc.adoc59
-rw-r--r--docs/man/nng_ipc_getopt.3ipc.adoc70
-rw-r--r--docs/man/nng_ipc_listener.5.adoc52
-rw-r--r--docs/man/nng_ipc_listener_accept.3ipc.adoc63
-rw-r--r--docs/man/nng_ipc_listener_alloc.3ipc.adoc50
-rw-r--r--docs/man/nng_ipc_listener_close.3ipc.adoc57
-rw-r--r--docs/man/nng_ipc_listener_free.3ipc.adoc52
-rw-r--r--docs/man/nng_ipc_listener_getopt.3ipc.adoc66
-rw-r--r--docs/man/nng_ipc_listener_listen.3ipc.adoc56
-rw-r--r--docs/man/nng_ipc_listener_setopt.3ipc.adoc64
-rw-r--r--docs/man/nng_ipc_recv.3ipc.adoc72
-rw-r--r--docs/man/nng_ipc_setopt.3ipc.adoc57
-rw-r--r--docs/man/nng_stream.5.adoc80
-rw-r--r--docs/man/nng_stream_close.3str.adoc (renamed from docs/man/nng_tls_close.3tls.adoc)30
-rw-r--r--docs/man/nng_stream_dialer.5.adoc46
-rw-r--r--docs/man/nng_stream_dialer_alloc.3str.adoc68
-rw-r--r--docs/man/nng_stream_dialer_close.3str.adoc (renamed from docs/man/nng_tls_dialer_close.3tls.adoc)28
-rw-r--r--docs/man/nng_stream_dialer_dial.3str.adoc (renamed from docs/man/nng_tls_dialer_dial.3tls.adoc)38
-rw-r--r--docs/man/nng_stream_dialer_free.3str.adoc (renamed from docs/man/nng_tls_dialer_free.3tls.adoc)25
-rw-r--r--docs/man/nng_stream_dialer_get.3str.adoc143
-rw-r--r--docs/man/nng_stream_dialer_set.3str.adoc133
-rw-r--r--docs/man/nng_stream_free.3str.adoc (renamed from docs/man/nng_tls_free.3tls.adoc)30
-rw-r--r--docs/man/nng_stream_get.3str.adoc146
-rw-r--r--docs/man/nng_stream_listener.5.adoc48
-rw-r--r--docs/man/nng_stream_listener_accept.3str.adoc64
-rw-r--r--docs/man/nng_stream_listener_alloc.3str.adoc70
-rw-r--r--docs/man/nng_stream_listener_close.3str.adoc (renamed from docs/man/nng_tls_listener_close.3tls.adoc)28
-rw-r--r--docs/man/nng_stream_listener_free.3str.adoc (renamed from docs/man/nng_ipc_dialer_free.3ipc.adoc)28
-rw-r--r--docs/man/nng_stream_listener_get.3str.adoc144
-rw-r--r--docs/man/nng_stream_listener_listen.3str.adoc66
-rw-r--r--docs/man/nng_stream_listener_set.3str.adoc133
-rw-r--r--docs/man/nng_stream_recv.3str.adoc (renamed from docs/man/nng_tcp_recv.3tcp.adoc)39
-rw-r--r--docs/man/nng_stream_send.3str.adoc (renamed from docs/man/nng_ipc_send.3ipc.adoc)39
-rw-r--r--docs/man/nng_stream_set.3str.adoc133
-rw-r--r--docs/man/nng_tcp_close.3tcp.adoc60
-rw-r--r--docs/man/nng_tcp_dialer.5.adoc49
-rw-r--r--docs/man/nng_tcp_dialer_alloc.3tcp.adoc50
-rw-r--r--docs/man/nng_tcp_dialer_close.3tcp.adoc57
-rw-r--r--docs/man/nng_tcp_dialer_dial.3tcp.adoc63
-rw-r--r--docs/man/nng_tcp_dialer_free.3tcp.adoc52
-rw-r--r--docs/man/nng_tcp_dialer_getopt.3tcp.adoc69
-rw-r--r--docs/man/nng_tcp_dialer_setopt.3tcp.adoc63
-rw-r--r--docs/man/nng_tcp_free.3tcp.adoc58
-rw-r--r--docs/man/nng_tcp_getopt.3tcp.adoc68
-rw-r--r--docs/man/nng_tcp_listener.5.adoc52
-rw-r--r--docs/man/nng_tcp_listener_accept.3tcp.adoc67
-rw-r--r--docs/man/nng_tcp_listener_alloc.3tcp.adoc51
-rw-r--r--docs/man/nng_tcp_listener_close.3tcp.adoc57
-rw-r--r--docs/man/nng_tcp_listener_free.3tcp.adoc51
-rw-r--r--docs/man/nng_tcp_listener_getopt.3tcp.adoc69
-rw-r--r--docs/man/nng_tcp_listener_listen.3tcp.adoc71
-rw-r--r--docs/man/nng_tcp_listener_setopt.3tcp.adoc62
-rw-r--r--docs/man/nng_tcp_send.3tcp.adoc73
-rw-r--r--docs/man/nng_tcp_setopt.3tcp.adoc61
-rw-r--r--docs/man/nng_tls_dialer.5.adoc51
-rw-r--r--docs/man/nng_tls_dialer_alloc.3tls.adoc52
-rw-r--r--docs/man/nng_tls_dialer_getopt.3tls.adoc73
-rw-r--r--docs/man/nng_tls_dialer_setopt.3tls.adoc69
-rw-r--r--docs/man/nng_tls_getopt.3tls.adoc70
-rw-r--r--docs/man/nng_tls_listener.5.adoc53
-rw-r--r--docs/man/nng_tls_listener_accept.3tls.adoc70
-rw-r--r--docs/man/nng_tls_listener_alloc.3tls.adoc53
-rw-r--r--docs/man/nng_tls_listener_free.3tls.adoc52
-rw-r--r--docs/man/nng_tls_listener_getopt.3tls.adoc72
-rw-r--r--docs/man/nng_tls_listener_listen.3tls.adoc73
-rw-r--r--docs/man/nng_tls_listener_setopt.3tls.adoc67
-rw-r--r--docs/man/nng_tls_recv.3tls.adoc73
-rw-r--r--docs/man/nng_tls_send.3tls.adoc72
-rw-r--r--docs/man/nng_tls_setopt.3tls.adoc61
-rw-r--r--include/nng/nng.h156
-rw-r--r--include/nng/supplemental/ipc/ipc.h133
-rw-r--r--include/nng/supplemental/tcp/tcp.h154
-rw-r--r--include/nng/supplemental/tls/tls.h68
-rw-r--r--include/nng/transport/tcp/tcp.h2
-rw-r--r--include/nng/transport/ws/websocket.h8
-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
-rw-r--r--tests/ipcsupp.c75
-rw-r--r--tests/resolv.c16
-rw-r--r--tests/stubs.h9
-rw-r--r--tests/tcpsupp.c99
145 files changed, 6587 insertions, 8320 deletions
diff --git a/docs/man/CMakeLists.txt b/docs/man/CMakeLists.txt
index 9a2cc5dd..747e1bad 100644
--- a/docs/man/CMakeLists.txt
+++ b/docs/man/CMakeLists.txt
@@ -1,6 +1,6 @@
#
+# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2019 Devolutions <info@devolutions.net>
#
# This software is supplied under the terms of the MIT License, a
@@ -272,28 +272,6 @@ if (NNG_ENABLE_DOC)
nng_http_server_stop
)
- set(NNG_MAN3IPC
- nng_ipc_close
- nng_ipc_free
- nng_ipc_getopt
- nng_ipc_dialer_alloc
- nng_ipc_dialer_close
- nng_ipc_dialer_dial
- nng_ipc_dialer_free
- nng_ipc_dialer_getopt
- nng_ipc_dialer_setopt
- nng_ipc_listener_accept
- nng_ipc_listener_alloc
- nng_ipc_listener_close
- nng_ipc_listener_free
- nng_ipc_listener_getopt
- nng_ipc_listener_listen
- nng_ipc_listener_setopt
- nng_ipc_recv
- nng_ipc_send
- nng_ipc_setopt
- )
-
set(NNG_MAN3SUPP
nng_clock
nng_cv_alloc
@@ -313,30 +291,29 @@ if (NNG_ENABLE_DOC)
nng_thread_destroy
)
- set(NNG_MAN3TCP
- nng_tcp_close
- nng_tcp_free
- nng_tcp_getopt
- nng_tcp_dialer_alloc
- nng_tcp_dialer_close
- nng_tcp_dialer_dial
- nng_tcp_dialer_free
- nng_tcp_dialer_getopt
- nng_tcp_dialer_setopt
- nng_tcp_listener_accept
- nng_tcp_listener_alloc
- nng_tcp_listener_close
- nng_tcp_listener_free
- nng_tcp_listener_getopt
- nng_tcp_listener_listen
- nng_tcp_listener_setopt
- nng_tcp_recv
- nng_tcp_send
- nng_tcp_setopt
+ set(NNG_MAN3STR
+ nng_stream_close
+ nng_stream_free
+ nng_stream_get
+ nng_stream_recv
+ nng_stream_send
+ nng_stream_set
+ nng_stream_dialer_alloc
+ nng_stream_dialer_close
+ nng_stream_dialer_dial
+ nng_stream_dialer_free
+ nng_stream_dialer_get
+ nng_stream_dialer_set
+ nng_stream_listener_accept
+ nng_stream_listener_alloc
+ nng_stream_listener_close
+ nng_stream_listener_free
+ nng_stream_listener_get
+ nng_stream_listener_listen
+ nng_stream_listener_set
)
set(NNG_MAN3TLS
- nng_tls_close
nng_tls_config_alloc
nng_tls_config_auth_mode
nng_tls_config_ca_chain
@@ -346,24 +323,6 @@ if (NNG_ENABLE_DOC)
nng_tls_config_hold
nng_tls_config_own_cert
nng_tls_config_server_name
- nng_tls_free
- nng_tls_getopt
- nng_tls_dialer_alloc
- nng_tls_dialer_close
- nng_tls_dialer_dial
- nng_tls_dialer_free
- nng_tls_dialer_getopt
- nng_tls_dialer_setopt
- nng_tls_listener_accept
- nng_tls_listener_alloc
- nng_tls_listener_close
- nng_tls_listener_free
- nng_tls_listener_getopt
- nng_tls_listener_listen
- nng_tls_listener_setopt
- nng_tls_recv
- nng_tls_send
- nng_tls_setopt
)
set(NNG_MAN5
@@ -385,20 +344,13 @@ if (NNG_ENABLE_DOC)
nng_socket
nng_stat
- nng_tcp
- nng_tcp_dialer
- nng_tcp_listener
- nng_tcp_options
+ nng_stream
+ nng_stream_dialer
+ nng_stream_listener
- nng_ipc
- nng_ipc_dialer
- nng_ipc_listener
+ nng_tcp_options
nng_ipc_options
-
- nng_tls
nng_tls_config
- nng_tls_dialer
- nng_tls_listener
nng_tls_options
)
@@ -438,18 +390,14 @@ if (NNG_ENABLE_DOC)
nng_man(${F} 3http)
endforeach()
- foreach(F ${NNG_MAN3IPC})
- nng_man(${F} 3ipc)
+ foreach(F ${NNG_MAN3STR})
+ nng_man(${F} 3str)
endforeach()
foreach(F ${NNG_MAN3SUPP})
nng_man(${F} 3supp)
endforeach()
- foreach(F ${NNG_MAN3TCP})
- nng_man(${F} 3tcp)
- endforeach()
-
foreach(F ${NNG_MAN3TLS})
nng_man(${F} 3tls)
endforeach()
diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc
index 49b9b78a..3aebcf76 100644
--- a/docs/man/libnng.3.adoc
+++ b/docs/man/libnng.3.adoc
@@ -20,7 +20,7 @@ libnng - nanomsg next generation library
== DESCRIPTION
-The <<nng.7#,_nng_>> library provides a common messaging framework
+The xref:nng.7.adoc[_nng_] library provides a common messaging framework
intended to solve common communication problems in distributed applications.
It provides a C language API.
@@ -30,12 +30,12 @@ It provides a C language API.
The following common functions exist in _libnng_.
|===
-|<<nng_alloc.3#,nng_alloc()>>|allocate memory
-|<<nng_free.3#,nng_free()>>|free memory
-|<<nng_strdup.3#,nng_strdup()>>|duplicate string
-|<<nng_strerror.3#,nng_strerror()>>|return an error description
-|<<nng_strfree.3#,nng_strfree()>>|free string
-|<<nng_version.3#,nng_version()>>|report library version
+|xref:nng_alloc.3.adoc[nng_alloc()]|allocate memory
+|xref:nng_free.3.adoc[nng_free()]|free memory
+|xref:nng_strdup.3.adoc[nng_strdup()]|duplicate string
+|xref:nng_strerror.3.adoc[nng_strerror()]|return an error description
+|xref:nng_strfree.3.adoc[nng_strfree()]|free string
+|xref:nng_version.3.adoc[nng_version()]|report library version
|===
=== Socket Functions
@@ -43,14 +43,14 @@ The following common functions exist in _libnng_.
The following functions operate on sockets.
|===
-|<<nng_close.3#,nng_close()>>|close socket
-|<<nng_dial.3#,nng_dial()>>|create and start dialer
-|<<nng_getopt.3#,nng_getopt()>>|get socket option
-|<<nng_listen.3#,nng_listen()>>|create and start listener
-|<<nng_recv.3#,nng_recv()>>|receive data
-|<<nng_send.3#,nng_send()>>|send data
-|<<nng_setopt.3#,nng_setopt()>>|set socket option
-|<<nng_socket_id.3#,nng_socket_id()>>|get numeric socket identifier
+|xref:nng_close.3.adoc[nng_close()]|close socket
+|xref:nng_dial.3.adoc[nng_dial()]|create and start dialer
+|xref:nng_getopt.3.adoc[nng_getopt()]|get socket option
+|xref:nng_listen.3.adoc[nng_listen()]|create and start listener
+|xref:nng_recv.3.adoc[nng_recv()]|receive data
+|xref:nng_send.3.adoc[nng_send()]|send data
+|xref:nng_setopt.3.adoc[nng_setopt()]|set socket option
+|xref:nng_socket_id.3.adoc[nng_socket_id()]|get numeric socket identifier
|===
=== Connection Management
@@ -59,27 +59,27 @@ The following functions are used with either listeners, or dialers.
Listeners accept incoming connection requests, and dialers make them.
|===
-|<<nng_dial.3#,nng_dial()>>|create and start dialer
-|<<nng_dialer_close.3#,nng_dialer_close()>>|close dialer
-|<<nng_dialer_create.3#,nng_dialer_create()>>|create dialer
-|<<nng_dialer_getopt.3#,nng_dialer_getopt()>>|get dialer option
-|<<nng_dialer_id.3#,nng_dialer_id()>>|get numeric dialer identifier
-|<<nng_dialer_setopt.3#,nng_dialer_setopt()>>|set dialer option
-|<<nng_dialer_start.3#,nng_dialer_start()>>|start dialer
-|<<nng_listen.3#,nng_listen()>>|create and start listener
-|<<nng_listener_close.3#,nng_listener_close()>>|close listener
-|<<nng_listener_create.3#,nng_listener_create()>>|create listener
-|<<nng_listener_getopt.3#,nng_listener_getopt()>>|get listener option
-|<<nng_listener_id.3#,nng_listener_id()>>|get numeric listener identifier
-|<<nng_listener_setopt.3#,nng_listener_setopt()>>|set listener option
-|<<nng_listener_start.3#,nng_listener_start()>>|start listener
-|<<nng_pipe_close.3#,nng_pipe_close()>>|close pipe
-|<<nng_pipe_dialer.3#,nng_pipe_dialer()>>|return dialer that created pipe
-|<<nng_pipe_getopt.3#,nng_pipe_getopt()>>|get pipe option
-|<<nng_pipe_id.3#,nng_pipe_id()>>|get numeric pipe identifier
-|<<nng_pipe_listener.3#,nng_pipe_listener()>>|return listener that created pipe
-|<<nng_pipe_notify.3#,nng_pipe_notify()>>|register pipe notification callback
-|<<nng_pipe_socket.3#,nng_pipe_socket()>>|return owning socket for pipe
+|xref:nng_dial.3.adoc[nng_dial()]|create and start dialer
+|xref:nng_dialer_close.3.adoc[nng_dialer_close()]|close dialer
+|xref:nng_dialer_create.3.adoc[nng_dialer_create()]|create dialer
+|xref:nng_dialer_getopt.3.adoc[nng_dialer_getopt()]|get dialer option
+|xref:nng_dialer_id.3.adoc[nng_dialer_id()]|get numeric dialer identifier
+|xref:nng_dialer_setopt.3.adoc[nng_dialer_setopt()]|set dialer option
+|xref:nng_dialer_start.3.adoc[nng_dialer_start()]|start dialer
+|xref:nng_listen.3.adoc[nng_listen()]|create and start listener
+|xref:nng_listener_close.3.adoc[nng_listener_close()]|close listener
+|xref:nng_listener_create.3.adoc[nng_listener_create()]|create listener
+|xref:nng_listener_getopt.3.adoc[nng_listener_getopt()]|get listener option
+|xref:nng_listener_id.3.adoc[nng_listener_id()]|get numeric listener identifier
+|xref:nng_listener_setopt.3.adoc[nng_listener_setopt()]|set listener option
+|xref:nng_listener_start.3.adoc[nng_listener_start()]|start listener
+|xref:nng_pipe_close.3.adoc[nng_pipe_close()]|close pipe
+|xref:nng_pipe_dialer.3.adoc[nng_pipe_dialer()]|return dialer that created pipe
+|xref:nng_pipe_getopt.3.adoc[nng_pipe_getopt()]|get pipe option
+|xref:nng_pipe_id.3.adoc[nng_pipe_id()]|get numeric pipe identifier
+|xref:nng_pipe_listener.3.adoc[nng_pipe_listener()]|return listener that created pipe
+|xref:nng_pipe_notify.3.adoc[nng_pipe_notify()]|register pipe notification callback
+|xref:nng_pipe_socket.3.adoc[nng_pipe_socket()]|return owning socket for pipe
|===
=== Message Handling Functions
@@ -93,21 +93,21 @@ user-payload and the header carries protocol specific header information.
Most applications will only interact with the body.
|===
-|<<nng_msg_alloc.3#,nng_msg_alloc()>>|allocate a message
-|<<nng_msg_append.3#,nng_msg_append()>>|append to message body
-|<<nng_msg_body.3#,nng_msg_body()>>|return message body
-|<<nng_msg_chop.3#,nng_msg_chop()>>|remove data from end of message body
-|<<nng_msg_clear.3#,nng_msg_clear()>>|clear message body
-|<<nng_msg_dup.3#,nng_msg_dup()>>|duplicate a message
-|<<nng_msg_free.3#,nng_msg_free()>>|free a message
-|<<nng_msg_get_pipe.3#,nng_msg_get_pipe()>>|get pipe for message
-|<<nng_msg_insert.3#,nng_msg_insert()>>|prepend to message body
-|<<nng_msg_len.3#,nng_msg_len()>>|return the message body length
-|<<nng_msg_realloc.3#,nng_msg_realloc()>>|reallocate a message
-|<<nng_msg_set_pipe.3#,nng_msg_set_pipe()>>|set pipe for message
-|<<nng_msg_trim.3#,nng_msg_trim()>>|remove data from start of message body
-|<<nng_recvmsg.3#,nng_recvmsg()>>|receive a message
-|<<nng_sendmsg.3#,nng_sendmsg()>>|send a message
+|xref:nng_msg_alloc.3.adoc[nng_msg_alloc()]|allocate a message
+|xref:nng_msg_append.3.adoc[nng_msg_append()]|append to message body
+|xref:nng_msg_body.3.adoc[nng_msg_body()]|return message body
+|xref:nng_msg_chop.3.adoc[nng_msg_chop()]|remove data from end of message body
+|xref:nng_msg_clear.3.adoc[nng_msg_clear()]|clear message body
+|xref:nng_msg_dup.3.adoc[nng_msg_dup()]|duplicate a message
+|xref:nng_msg_free.3.adoc[nng_msg_free()]|free a message
+|xref:nng_msg_get_pipe.3.adoc[nng_msg_get_pipe()]|get pipe for message
+|xref:nng_msg_insert.3.adoc[nng_msg_insert()]|prepend to message body
+|xref:nng_msg_len.3.adoc[nng_msg_len()]|return the message body length
+|xref:nng_msg_realloc.3.adoc[nng_msg_realloc()]|reallocate a message
+|xref:nng_msg_set_pipe.3.adoc[nng_msg_set_pipe()]|set pipe for message
+|xref:nng_msg_trim.3.adoc[nng_msg_trim()]|remove data from start of message body
+|xref:nng_recvmsg.3.adoc[nng_recvmsg()]|receive a message
+|xref:nng_sendmsg.3.adoc[nng_sendmsg()]|send a message
|===
==== Message Header Handling
@@ -117,19 +117,19 @@ used to carry protocol-specific content. However, applications which use raw
mode may need to access the header of messages.
|===
-|<<nng_msg_header.3#,nng_msg_header()>>|return message header
-|<<nng_msg_header_append.3#,nng_msg_header_append()>>|append to message header
-|<<nng_msg_header_chop.3#,nng_msg_header_chop()>>|remove data from end of message header
-|<<nng_msg_header_clear.3#,nng_msg_header_clear()>>|clear message header
-|<<nng_msg_header_insert.3#,nng_msg_header_insert()>>|prepend to message header
-|<<nng_msg_header_len.3#,nng_msg_header_len()>>|return the message header length
-|<<nng_msg_header_trim.3#,nng_msg_header_trim()>>|remove data from start of message header
+|xref:nng_msg_header.3.adoc[nng_msg_header()]|return message header
+|xref:nng_msg_header_append.3.adoc[nng_msg_header_append()]|append to message header
+|xref:nng_msg_header_chop.3.adoc[nng_msg_header_chop()]|remove data from end of message header
+|xref:nng_msg_header_clear.3.adoc[nng_msg_header_clear()]|clear message header
+|xref:nng_msg_header_insert.3.adoc[nng_msg_header_insert()]|prepend to message header
+|xref:nng_msg_header_len.3.adoc[nng_msg_header_len()]|return the message header length
+|xref:nng_msg_header_trim.3.adoc[nng_msg_header_trim()]|remove data from start of message header
|===
=== Asynchronous Operations
Most applications will interact with _nng_ synchronously; that is that
-functions such as <<nng_send.3#,`nng_send()`>> will block the calling
+functions such as xref:nng_send.3.adoc[`nng_send()`] will block the calling
thread until the operation has completed.
NOTE: Synchronous operations which send messages may return before the
@@ -143,7 +143,7 @@ the calling thread. When the operation is subsequently completed (regardless
of whether this was successful or not), then a user supplied function
("`callback`") is executed.
-A context structure, an <<nng_aio.5#,`nng_aio`>>, is allocated and
+A context structure, an xref:nng_aio.5.adoc[`nng_aio`], is allocated and
associated with each asynchronous operation.
Only a single asynchronous operation may be associated with an
`nng_aio` at any time.
@@ -151,28 +151,28 @@ Only a single asynchronous operation may be associated with an
The following functions are used in the asynchronous model:
|===
-|<<nng_aio_abort.3#,nng_aio_abort()>>|abort asynchronous I/O operation
-|<<nng_aio_alloc.3#,nng_aio_alloc()>>|allocate asynchronous I/O handle
-|<<nng_aio_begin.3#,nng_aio_begin()>>|begin asynchronous I/O operation
-|<<nng_aio_cancel.3#,nng_aio_cancel()>>|cancel asynchronous I/O operation
-|<<nng_aio_count.3#,nng_aio_count()>>|return number of bytes transferred
-|<<nng_aio_defer.3#,nng_aio_defer()>>|defer asynchronous I/O operation
-|<<nng_aio_finish.3#,nng_aio_finish()>>|finish asynchronous I/O operation
-|<<nng_aio_free.3#,nng_aio_free()>>|free asynchronous I/O handle
-|<<nng_aio_get_input.3#,nng_aio_get_input()>>|return input parameter
-|<<nng_aio_get_msg.3#,nng_aio_get_msg()>>|get message from an asynchronous receive
-|<<nng_aio_get_output.3#,nng_aio_get_output()>>|return output result
-|<<nng_aio_result.3#,nng_aio_result()>>|return result of asynchronous operation
-|<<nng_aio_set_input.3#,nng_aio_set_input()>>|set input parameter
-|<<nng_aio_set_iov.3#,nng_aio_set_iov()>>|set scatter/gather vector
-|<<nng_aio_set_msg.3#,nng_aio_set_msg()>>|set message for an asynchronous send
-|<<nng_aio_set_output.3#,nng_aio_set_output()>>|set output result
-|<<nng_aio_set_timeout.3#,nng_aio_set_timeout()>>|set asynchronous I/O timeout
-|<<nng_aio_stop.3#,nng_aio_stop()>>|stop asynchronous I/O operation
-|<<nng_aio_wait.3#,nng_aio_wait()>>|wait for asynchronous I/O operation
-|<<nng_recv_aio.3#,nng_recv_aio()>>|receive message asynchronously
-|<<nng_send_aio.3#,nng_send_aio()>>|send message asynchronously
-|<<nng_sleep_aio.3#,nng_sleep_aio()>>|sleep asynchronously
+|xref:nng_aio_abort.3.adoc[nng_aio_abort()]|abort asynchronous I/O operation
+|xref:nng_aio_alloc.3.adoc[nng_aio_alloc()]|allocate asynchronous I/O handle
+|xref:nng_aio_begin.3.adoc[nng_aio_begin()]|begin asynchronous I/O operation
+|xref:nng_aio_cancel.3.adoc[nng_aio_cancel()]|cancel asynchronous I/O operation
+|xref:nng_aio_count.3.adoc[nng_aio_count()]|return number of bytes transferred
+|xref:nng_aio_defer.3.adoc[nng_aio_defer()]|defer asynchronous I/O operation
+|xref:nng_aio_finish.3.adoc[nng_aio_finish()]|finish asynchronous I/O operation
+|xref:nng_aio_free.3.adoc[nng_aio_free()]|free asynchronous I/O handle
+|xref:nng_aio_get_input.3.adoc[nng_aio_get_input()]|return input parameter
+|xref:nng_aio_get_msg.3.adoc[nng_aio_get_msg()]|get message from an asynchronous receive
+|xref:nng_aio_get_output.3.adoc[nng_aio_get_output()]|return output result
+|xref:nng_aio_result.3.adoc[nng_aio_result()]|return result of asynchronous operation
+|xref:nng_aio_set_input.3.adoc[nng_aio_set_input()]|set input parameter
+|xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov()]|set scatter/gather vector
+|xref:nng_aio_set_msg.3.adoc[nng_aio_set_msg()]|set message for an asynchronous send
+|xref:nng_aio_set_output.3.adoc[nng_aio_set_output()]|set output result
+|xref:nng_aio_set_timeout.3.adoc[nng_aio_set_timeout()]|set asynchronous I/O timeout
+|xref:nng_aio_stop.3.adoc[nng_aio_stop()]|stop asynchronous I/O operation
+|xref:nng_aio_wait.3.adoc[nng_aio_wait()]|wait for asynchronous I/O operation
+|xref:nng_recv_aio.3.adoc[nng_recv_aio()]|receive message asynchronously
+|xref:nng_send_aio.3.adoc[nng_send_aio()]|send message asynchronously
+|xref:nng_sleep_aio.3.adoc[nng_sleep_aio()]|sleep asynchronously
|===
=== Protocols
@@ -180,16 +180,16 @@ The following functions are used in the asynchronous model:
The following functions are used to construct a socket with a specific protocol:
|===
-|<<nng_bus_open.3#,nng_bus_open()>>|open a bus socket
-|<<nng_pair_open.3#,nng_pair_open()>>|open a pair socket
-|<<nng_pub_open.3#,nng_pub_open()>>|open a pub socket
-|<<nng_pull_open.3#,nng_pull_open()>>|open a pull socket
-|<<nng_push_open.3#,nng_push_open()>>|open a push socket
-|<<nng_rep_open.3#,nng_rep_open()>>|open a rep socket
-|<<nng_req_open.3#,nng_req_open()>>|open a req socket
-|<<nng_respondent_open.3#,nng_respondent_open()>>|open a respondent socket
-|<<nng_sub_open.3#,nng_sub_open()>>|open a sub socket
-|<<nng_surveyor_open.3#,nng_surveyor_open()>>|open a surveyor socket
+|xref:nng_bus_open.3.adoc[nng_bus_open()]|open a bus socket
+|xref:nng_pair_open.3.adoc[nng_pair_open()]|open a pair socket
+|xref:nng_pub_open.3.adoc[nng_pub_open()]|open a pub socket
+|xref:nng_pull_open.3.adoc[nng_pull_open()]|open a pull socket
+|xref:nng_push_open.3.adoc[nng_push_open()]|open a push socket
+|xref:nng_rep_open.3.adoc[nng_rep_open()]|open a rep socket
+|xref:nng_req_open.3.adoc[nng_req_open()]|open a req socket
+|xref:nng_respondent_open.3.adoc[nng_respondent_open()]|open a respondent socket
+|xref:nng_sub_open.3.adoc[nng_sub_open()]|open a sub socket
+|xref:nng_surveyor_open.3.adoc[nng_surveyor_open()]|open a surveyor socket
|===
=== Transports
@@ -197,13 +197,13 @@ The following functions are used to construct a socket with a specific protocol:
The following functions are used to register a transport for use.
|===
-| <<nng_inproc_register.3#,nng_inproc_register()>>|register inproc transport
-| <<nng_ipc_register.3#,nng_ipc_register()>>|register IPC transport
-| <<nng_tcp_register.3#,nng_tcp_register()>>|register TCP transport
-| <<nng_tls_register.3#,nng_tls_register()>>|register TLS transport
-| <<nng_ws_register.3#,nng_ws_register()>>|register WebSocket transport
-| <<nng_wss_register.3#,nng_wss_register()>>|register WebSocket Secure transport
-| <<nng_zt_register.3#,nng_zt_register()>>|register ZeroTier transport
+| xref:nng_inproc_register.3.adoc[nng_inproc_register()]|register inproc transport
+| xref:nng_ipc_register.3.adoc[nng_ipc_register()]|register IPC transport
+| xref:nng_tcp_register.3.adoc[nng_tcp_register()]|register TCP transport
+| xref:nng_tls_register.3.adoc[nng_tls_register()]|register TLS transport
+| xref:nng_ws_register.3.adoc[nng_ws_register()]|register WebSocket transport
+| xref:nng_wss_register.3.adoc[nng_wss_register()]|register WebSocket Secure transport
+| xref:nng_zt_register.3.adoc[nng_zt_register()]|register ZeroTier transport
|===
=== Protocol Contexts
@@ -214,13 +214,13 @@ This can allow multiple contexts to be created on a single socket for
concurrent applications.
|===
-|<<nng_ctx_close.3#,nng_ctx_close()>>|close context
-|<<nng_ctx_getopt.3#,nng_ctx_getopt()>>|get context option
-|<<nng_ctx_id.3#,nng_ctx_id()>>|get numeric context identifier
-|<<nng_ctx_open.3#,nng_ctx_open()>>|create context
-|<<nng_ctx_recv.3#,nng_ctx_recv()>>|receive message using context asynchronously
-|<<nng_ctx_send.3#,nng_ctx_send()>>|send message using context asynchronously
-|<<nng_ctx_setopt.3#,nng_ctx_setopt()>>|set context option
+|xref:nng_ctx_close.3.adoc[nng_ctx_close()]|close context
+|xref:nng_ctx_getopt.3.adoc[nng_ctx_getopt()]|get context option
+|xref:nng_ctx_id.3.adoc[nng_ctx_id()]|get numeric context identifier
+|xref:nng_ctx_open.3.adoc[nng_ctx_open()]|create context
+|xref:nng_ctx_recv.3.adoc[nng_ctx_recv()]|receive message using context asynchronously
+|xref:nng_ctx_send.3.adoc[nng_ctx_send()]|send message using context asynchronously
+|xref:nng_ctx_setopt.3.adoc[nng_ctx_setopt()]|set context option
|===
=== Statistics
@@ -229,17 +229,17 @@ The following functions provide access to statistics which can be used
to observe program behaviors and as an aid in troubleshooting.
|===
-|<<nng_stat_child.3#,nng_stat_child()>>|get child statistic
-|<<nng_stat_desc.3#,nng_stat_name()>>|get statistic description
-|<<nng_stat_name.3#,nng_stat_name()>>|get statistic name
-|<<nng_stat_next.3#,nng_stat_next()>>|get next statistic
-|<<nng_stat_string.3#,nng_stat_string()>>|get statistic string value
-|<<nng_stat_timestamp.3#,nng_stat_timestamp()>>|get statistic timestamp
-|<<nng_stat_type.3#,nng_stat_type()>>|get statistic type
-|<<nng_stat_unit.3#,nng_stat_unit()>>|get statistic unit
-|<<nng_stat_value.3#,nng_stat_valueg()>>|get statistic value
-|<<nng_stats_free.3#,nng_stats_free()>>|free statistics
-|<<nng_stats_get.3#,nng_stats_get()>>|get statistics
+|xref:nng_stat_child.3.adoc[nng_stat_child()]|get child statistic
+|xref:nng_stat_desc.3.adoc[nng_stat_name()]|get statistic description
+|xref:nng_stat_name.3.adoc[nng_stat_name()]|get statistic name
+|xref:nng_stat_next.3.adoc[nng_stat_next()]|get next statistic
+|xref:nng_stat_string.3.adoc[nng_stat_string()]|get statistic string value
+|xref:nng_stat_timestamp.3.adoc[nng_stat_timestamp()]|get statistic timestamp
+|xref:nng_stat_type.3.adoc[nng_stat_type()]|get statistic type
+|xref:nng_stat_unit.3.adoc[nng_stat_unit()]|get statistic unit
+|xref:nng_stat_value.3.adoc[nng_stat_valueg()]|get statistic value
+|xref:nng_stats_free.3.adoc[nng_stats_free()]|free statistics
+|xref:nng_stats_get.3.adoc[nng_stats_get()]|get statistics
|===
=== URL Object
@@ -248,9 +248,9 @@ Common functionality is supplied for parsing and handling
universal resource locators (URLS).
|===
-|<<nng_url_clone.3#,nng_url_clone()>>|clone URL structure
-|<<nng_url_free.3#,nng_url_free()>>|free URL structure
-|<<nng_url_parse.3#,nng_url_parse()>>|create URL structure from string
+|xref:nng_url_clone.3.adoc[nng_url_clone()]|clone URL structure
+|xref:nng_url_free.3.adoc[nng_url_free()]|free URL structure
+|xref:nng_url_parse.3.adoc[nng_url_parse()]|create URL structure from string
|===
@@ -261,79 +261,57 @@ network applications with _NNG_, but they are made available
as a convenience to aid in creating portable applications.
|===
-|<<nng_clock.3supp#,nng_clock()>>|get time
-|<<nng_cv_alloc.3supp#,nng_cv_alloc()>>|allocate condition variable
-|<<nng_cv_free.3supp#,nng_cv_free()>>|free condition variable
-|<<nng_cv_until.3supp#,nng_cv_until()>>|wait for condition or timeout
-|<<nng_cv_wait.3supp#,nng_cv_wait()>>|wait for condition
-|<<nng_cv_wake.3supp#,nng_cv_wake()>>|wake all waiters
-|<<nng_cv_wake1.3supp#,nng_cv_wake1()>>|wake one waiter
-|<<nng_msleep.3supp#,nng_msleep()>>|sleep for milliseconds
-|<<nng_mtx_alloc.3supp#,nng_mtx_alloc()>>|allocate mutex
-|<<nng_mtx_free.3supp#,nng_mtx_free()>>|free mutex
-|<<nng_mtx_lock.3supp#,nng_mtx_lock()>>|lock mutex
-|<<nng_mtx_unlock.3supp#,nng_mtx_unlock()>>|unlock mutex
-|<<nng_opts_parse.3supp#,nng_opts_parse()>>|parse command line options
-|<<nng_random.3supp#,nng_random()>>|get random number
-|<<nng_thread_create.3supp#,nng_thread_create()>>|create thread
-|<<nng_thread_destroy.3supp#,nng_thread_destroy()>>|reap thread
-|===
-
-
-=== Supplemental TCP
-
-These TCP functions are available for use with direct TCP access.
-Most applications won't need to use these.
-
-|===
-|<<nng_tcp_close.3tcp#,nng_tcp_close()>>|close TCP connection
-|<<nng_tcp_dialer_alloc.3tcp#,nng_tcp_dialer_alloc()>>|allocate TCP dialer
-|<<nng_tcp_dialer_close.3tcp#,nng_tcp_dialer_close()>>|close TCP dialer
-|<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial()>>|initiate outgoing TCP connection
-|<<nng_tcp_dialer_free.3tcp#,nng_tcp_dialer_free()>>|free TCP dialer
-|<<nng_tcp_dialer_getopt.3tcp#,nng_tcp_dialer_getopt()>>|get option from TCP dialer
-|<<nng_tcp_dialer_setopt.3tcp#,nng_tcp_dialer_setopt()>>|set option on TCP dialer
-|<<nng_tcp_free.3tcp#,nng_tcp_free()>>|free TCP connection
-|<<nng_tcp_getopt.3tcp#,nng_tcp_getopt()>>|get option from TCP connection
-|<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept()>>|accept incoming TCP connection
-|<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc()>>|allocate TCP listener
-|<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close()>>|close TCP listener
-|<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free()>>|free TCP listener
-|<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt()>>|get option from TCP listener
-|<<nng_tcp_listener_listen.3tcp#,nng_tcp_listener_listen()>>|bind TCP listener to port
-|<<nng_tcp_listener_setopt.3tcp#,nng_tcp_listener_setopt()>>|set option on TCP listener
-|<<nng_tcp_recv.3tcp#,nng_tcp_recv()>>|receive from TCP connection
-|<<nng_tcp_send.3tcp#,nng_tcp_send()>>|send to TCP connection
-|<<nng_tcp_setopt.3tcp#,nng_tcp_setopt()>>|set option on TCP connection
-|===
-
-
-=== Supplemental IPC
-
-These IPC functions are available for use with direct interprocess
-communication (IPC).
-Most applications won't need to use these.
-
-|===
-|<<nng_ipc_close.3ipc#,nng_ipc_close()>>|close IPC connection
-|<<nng_ipc_dialer_alloc.3ipc#,nng_ipc_dialer_alloc()>>|allocate IPC dialer
-|<<nng_ipc_dialer_close.3ipc#,nng_ipc_dialer_close()>>|close IPC dialer
-|<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial()>>|initiate outgoing IPC connection
-|<<nng_ipc_dialer_free.3ipc#,nng_ipc_dialer_free()>>|free IPC dialer
-|<<nng_ipc_dialer_getopt.3ipc#,nng_ipc_dialer_getopt()>>|get option from IPC dialer
-|<<nng_ipc_dialer_setopt.3ipc#,nng_ipc_dialer_setopt()>>|set option on IPC dialer
-|<<nng_ipc_free.3ipc#,nng_ipc_free()>>|free IPC connection
-|<<nng_ipc_getopt.3ipc#,nng_ipc_getopt()>>|get option from IPC connection
-|<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept()>>|accept incoming IPC connection
-|<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc()>>|allocate IPC listener
-|<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close()>>|close IPC listener
-|<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free()>>|free IPC listener
-|<<nng_ipc_listener_getopt.3ipc#,nng_ipc_listener_getopt()>>|get option from IPC listener
-|<<nng_ipc_listener_listen.3ipc#,nng_ipc_listener_listen()>>|bind IPC listener
-|<<nng_ipc_listener_setopt.3ipc#,nng_ipc_listener_setopt()>>|set option on IPC listener
-|<<nng_ipc_recv.3ipc#,nng_ipc_recv()>>|receive from IPC connection
-|<<nng_ipc_send.3ipc#,nng_ipc_send()>>|send to IPC connection
-|<<nng_ipc_setopt.3ipc#,nng_ipc_setopt()>>|set option on IPC connection
+|xref:nng_clock.3supp.adoc[nng_clock()]|get time
+|xref:nng_cv_alloc.3supp.adoc[nng_cv_alloc()]|allocate condition variable
+|xref:nng_cv_free.3supp.adoc[nng_cv_free()]|free condition variable
+|xref:nng_cv_until.3supp.adoc[nng_cv_until()]|wait for condition or timeout
+|xref:nng_cv_wait.3supp.adoc[nng_cv_wait()]|wait for condition
+|xref:nng_cv_wake.3supp.adoc[nng_cv_wake()]|wake all waiters
+|xref:nng_cv_wake1.3supp.adoc[nng_cv_wake1()]|wake one waiter
+|xref:nng_msleep.3supp.adoc[nng_msleep()]|sleep for milliseconds
+|xref:nng_mtx_alloc.3supp.adoc[nng_mtx_alloc()]|allocate mutex
+|xref:nng_mtx_free.3supp.adoc[nng_mtx_free()]|free mutex
+|xref:nng_mtx_lock.3supp.adoc[nng_mtx_lock()]|lock mutex
+|xref:nng_mtx_unlock.3supp.adoc[nng_mtx_unlock()]|unlock mutex
+|xref:nng_opts_parse.3supp.adoc[nng_opts_parse()]|parse command line options
+|xref:nng_random.3supp.adoc[nng_random()]|get random number
+|xref:nng_thread_create.3supp.adoc[nng_thread_create()]|create thread
+|xref:nng_thread_destroy.3supp.adoc[nng_thread_destroy()]|reap thread
+|===
+
+=== Byte Streams
+
+These functions are available for use with byte streams.
+They are considered low-level, for uses where the higher level functions
+using Scalability Protocols are inappropriate.
+
+Byte streams, represented by
+xref:nng_stream.5.adoc[`nng_stream`] objects, correspond to underlying
+connections such as TCP connections or named pipes.
+They are created by either
+xref:nng_stream_dialer.5.adoc[`nng_stream_dialer`] or
+xref:nng_stream_listener.5.adoc[`nng_stream_listener`] objects.
+
+|===
+|xref:nng_stream_close.3str.adoc[nng_stream_close()]|close byte stream
+|xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc()]|allocate byte stream dialer
+|xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close()]|close byte stream dialer
+|xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial()]|initiate outgoing byte stream
+|xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free()]|free byte stream dialer
+|xref:nng_stream_dialer_get.3str.adoc[nng_stream_dialer_get()]|get option from byte stream dialer
+|xref:nng_stream_dialer_set.3str.adoc[nng_stream_dialer_set()]|set option on byte stream dialer
+|xref:nng_stream_free.3str.adoc[nng_stream_free()]|free byte stream
+|xref:nng_stream_get.3str.adoc[nng_stream_get()]|get option from byte stream
+|xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept()]|accept incoming byte stream
+|xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc()]|allocate byte stream listener
+|xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close()]|close byte stream listener
+|xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free()]|free byte stream listener
+|xref:nng_stream_listener_get.3str.adoc[nng_stream_listener_get()]|get option from byte stream listener
+|xref:nng_stream_listener_listen.3str.adoc[nng_stream_listener_listen()]|bind byte stream listener to address
+|xref:nng_stream_listener_set.3str.adoc[nng_stream_listener_set()]|set option on byte stream listener
+|xref:nng_stream_recv.3str.adoc[nng_stream_recv()]|receive from byte stream
+|xref:nng_stream_send.3str.adoc[nng_stream_send()]|send to byte stream
+|xref:nng_stream_set.3str.adoc[nng_stream_set()]|set option on byte stream
|===
=== HTTP Support
@@ -349,48 +327,48 @@ The following functions are used to work with HTTP requests, responses,
and connections.
|===
-|<<nng_http_conn_close.3http#,nng_http_conn_close()>>|close HTTP connection
-|<<nng_http_conn_read.3http#,nng_http_conn_read()>>|read from HTTP connection
-|<<nng_http_conn_read_all.3http#,nng_http_conn_read_all()>>|read all from HTTP connection
-|<<nng_http_conn_read_req.3http#,nng_http_conn_read_req()>>|read HTTP request
-|<<nng_http_conn_read_res.3http#,nng_http_conn_read_res()>>|read HTTP response
-|<<nng_http_conn_write.3http#,nng_http_conn_write()>>|write to HTTP connection
-|<<nng_http_conn_write_all.3http#,nng_http_conn_write_all()>>|write all to HTTP connection
-|<<nng_http_conn_write_req.3http#,nng_http_conn_write_req()>>|write HTTP request
-|<<nng_http_conn_write_res.3http#,nng_http_conn_write_res()>>|write HTTP response
-|<<nng_http_req_add_header.3http#,nng_http_req_add_header()>>|add HTTP request header
-|<<nng_http_req_alloc.3http#,nng_http_req_alloc()>>|allocate HTTP request structure
-|<<nng_http_req_copy_data.3http#,nng_http_req_copy_data()>>|copy HTTP request body
-|<<nng_http_req_del_header.3http#,nng_http_req_del_header()>>|delete HTTP request header
-|<<nng_http_req_free.3http#,nng_http_req_free()>>|free HTTP request structure
-|<<nng_http_req_get_data.3http#,nng_http_req_get_data()>>|get HTTP request body
-|<<nng_http_req_get_header.3http#,nng_http_req_get_header()>>|return HTTP request header
-|<<nng_http_req_get_method.3http#,nng_http_req_get_method()>>|return HTTP request method
-|<<nng_http_req_get_uri.3http#,nng_http_req_get_uri()>>|return HTTP request URI
-|<<nng_http_req_get_version.3http#,nng_http_req_get_version()>>|return HTTP request protocol version
-|<<nng_http_req_reset.3http#,nng_http_req_reset()>>|reset HTTP request structure
-|<<nng_http_req_set_data.3http#,nng_http_req_set_data()>>|set HTTP request body
-|<<nng_http_req_set_header.3http#,nng_http_req_set_header()>>|set HTTP request header
-|<<nng_http_req_set_method.3http#,nng_http_req_set_method()>>|set HTTP request method
-|<<nng_http_req_set_uri.3http#,nng_http_req_set_uri()>>|set HTTP request URI
-|<<nng_http_req_set_version.3http#,nng_http_req_set_version()>>|set HTTP request protocol version
-|<<nng_http_res_add_header.3http#,nng_http_res_add_header()>>|add HTTP response header
-|<<nng_http_res_alloc.3http#,nng_http_res_alloc()>>|allocate HTTP response structure
-|<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error()>>|allocate HTTP error response
-|<<nng_http_res_copy_data.3http#,nng_http_res_copy_data()>>|copy HTTP response body
-|<<nng_http_res_del_header.3http#,nng_http_res_del_header()>>|delete HTTP response header
-|<<nng_http_res_free.3http#,nng_http_res_free()>>|free HTTP response structure
-|<<nng_http_res_get_data.3http#,nng_http_res_get_data()>>|get HTTP response body
-|<<nng_http_res_get_header.3http#,nng_http_res_get_header()>>|return HTTP response header
-|<<nng_http_res_get_reason.3http#,nng_http_res_get_reason()>>|return HTTP response reason
-|<<nng_http_res_get_status.3http#,nng_http_res_get_status()>>|return HTTP response status
-|<<nng_http_res_get_version.3http#,nng_http_res_get_version()>>|return HTTP response protocol version
-|<<nng_http_res_reset.3http#,nng_http_res_reset()>>|reset HTTP response structure
-|<<nng_http_res_set_data.3http#,nng_http_res_set_data()>>|set HTTP response body
-|<<nng_http_res_set_header.3http#,nng_http_res_set_header()>>|set HTTP response header
-|<<nng_http_res_set_reason.3http#,nng_http_res_set_reason()>>|set HTTP response reason
-|<<nng_http_res_set_status.3http#,nng_http_res_set_status()>>|set HTTP response status
-|<<nng_http_res_set_version.3http#,nng_http_res_set_version()>>|set HTTP response protocol version
+|xref:nng_http_conn_close.3http.adoc[nng_http_conn_close()]|close HTTP connection
+|xref:nng_http_conn_read.3http.adoc[nng_http_conn_read()]|read from HTTP connection
+|xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all()]|read all from HTTP connection
+|xref:nng_http_conn_read_req.3http.adoc[nng_http_conn_read_req()]|read HTTP request
+|xref:nng_http_conn_read_res.3http.adoc[nng_http_conn_read_res()]|read HTTP response
+|xref:nng_http_conn_write.3http.adoc[nng_http_conn_write()]|write to HTTP connection
+|xref:nng_http_conn_write_all.3http.adoc[nng_http_conn_write_all()]|write all to HTTP connection
+|xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req()]|write HTTP request
+|xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res()]|write HTTP response
+|xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header()]|add HTTP request header
+|xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc()]|allocate HTTP request structure
+|xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data()]|copy HTTP request body
+|xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header()]|delete HTTP request header
+|xref:nng_http_req_free.3http.adoc[nng_http_req_free()]|free HTTP request structure
+|xref:nng_http_req_get_data.3http.adoc[nng_http_req_get_data()]|get HTTP request body
+|xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header()]|return HTTP request header
+|xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method()]|return HTTP request method
+|xref:nng_http_req_get_uri.3http.adoc[nng_http_req_get_uri()]|return HTTP request URI
+|xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version()]|return HTTP request protocol version
+|xref:nng_http_req_reset.3http.adoc[nng_http_req_reset()]|reset HTTP request structure
+|xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data()]|set HTTP request body
+|xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header()]|set HTTP request header
+|xref:nng_http_req_set_method.3http.adoc[nng_http_req_set_method()]|set HTTP request method
+|xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri()]|set HTTP request URI
+|xref:nng_http_req_set_version.3http.adoc[nng_http_req_set_version()]|set HTTP request protocol version
+|xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header()]|add HTTP response header
+|xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc()]|allocate HTTP response structure
+|xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error()]|allocate HTTP error response
+|xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data()]|copy HTTP response body
+|xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header()]|delete HTTP response header
+|xref:nng_http_res_free.3http.adoc[nng_http_res_free()]|free HTTP response structure
+|xref:nng_http_res_get_data.3http.adoc[nng_http_res_get_data()]|get HTTP response body
+|xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header()]|return HTTP response header
+|xref:nng_http_res_get_reason.3http.adoc[nng_http_res_get_reason()]|return HTTP response reason
+|xref:nng_http_res_get_status.3http.adoc[nng_http_res_get_status()]|return HTTP response status
+|xref:nng_http_res_get_version.3http.adoc[nng_http_res_get_version()]|return HTTP response protocol version
+|xref:nng_http_res_reset.3http.adoc[nng_http_res_reset()]|reset HTTP response structure
+|xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data()]|set HTTP response body
+|xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header()]|set HTTP response header
+|xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason()]|set HTTP response reason
+|xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status()]|set HTTP response status
+|xref:nng_http_res_set_version.3http.adoc[nng_http_res_set_version()]|set HTTP response protocol version
|===
==== HTTP Client Functions
@@ -398,13 +376,13 @@ and connections.
These functions are intended for use with HTTP client applications.
|===
-|<<nng_http_client_alloc.3http#,nng_http_client_alloc()>>|allocate HTTP client
-|<<nng_http_client_connect.3http#,nng_http_client_connect()>>|establish HTTP client connection
-|<<nng_http_client_free.3http#,nng_http_client_free()>>|free HTTP client
-|<<nng_http_client_get_tls.3http#,nng_http_client_get_tls()>>|get HTTP client TLS configuration
-|<<nng_http_client_set_tls.3http#,nng_http_client_set_tls()>>|set HTTP client TLS configuration
-|<<nng_http_client_transact.3http#,nng_http_client_transact()>>|perform one HTTP transaction
-|<<nng_http_conn_transact.3http#,nng_http_conn_transact()>>|perform one HTTP transaction on connection
+|xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc()]|allocate HTTP client
+|xref:nng_http_client_connect.3http.adoc[nng_http_client_connect()]|establish HTTP client connection
+|xref:nng_http_client_free.3http.adoc[nng_http_client_free()]|free HTTP client
+|xref:nng_http_client_get_tls.3http.adoc[nng_http_client_get_tls()]|get HTTP client TLS configuration
+|xref:nng_http_client_set_tls.3http.adoc[nng_http_client_set_tls()]|set HTTP client TLS configuration
+|xref:nng_http_client_transact.3http.adoc[nng_http_client_transact()]|perform one HTTP transaction
+|xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact()]|perform one HTTP transaction on connection
|===
==== HTTP Server Functions
@@ -412,26 +390,26 @@ These functions are intended for use with HTTP client applications.
These functions are intended for use with HTTP server applications.
|===
-|<<nng_http_handler_alloc.3http#,nng_http_handler_alloc()>>|allocate HTTP server handler
-|<<nng_http_handler_collect_body.3http#,nng_http_handler_collect_body()>>|set HTTP handler to collect request body
-|<<nng_http_handler_free.3http#,nng_http_handler_free()>>|free HTTP server handler
-|<<nng_http_handler_get_data.3http#,nng_http_handler_get_data()>>|return extra data for HTTP handler
-|<<nng_http_handler_set_data.3http#,nng_http_handler_set_data()>>|set extra data for HTTP handler
-|<<nng_http_handler_set_host.3http#,nng_http_handler_set_host()>>|set host for HTTP handler
-|<<nng_http_handler_set_method.3http#,nng_http_handler_set_method()>>|set HTTP handler method
-|<<nng_http_handler_set_tree.3http#,nng_http_handler_set_tree()>>|set HTTP handler to match trees
-|<<nng_http_hijack.3http#,nng_http_hijack()>>|hijack HTTP server connection
-|<<nng_http_server_add_handler.3http#,nng_http_server_add_handler()>>|add HTTP server handler
-|<<nng_http_server_del_handler.3http#,nng_http_server_del_handler()>>|delete HTTP server handler
-|<<nng_http_server_get_tls.3http#,nng_http_server_get_tls()>>|get HTTP server TLS configuration
-|<<nng_http_server_hold.3http#,nng_http_server_hold()>>|get and hold HTTP server instance
-|<<nng_http_server_release.3http#,nng_http_server_release()>>|release HTTP server instance
-|<<nng_http_server_set_error_file.3http#,nng_http_server_set_error_file()>>|set custom HTTP error file
-|<<nng_http_server_set_error_page.3http#,nng_http_server_set_error_page()>>|set custom HTTP error page
-|<<nng_http_server_set_tls.3http#,nng_http_server_set_tls()>>|set HTTP server TLS configuration
-|<<nng_http_server_res_error.3http#,nng_http_server_res_error()>>|use HTTP server error page
-|<<nng_http_server_start.3http#,nng_http_server_start()>>|start HTTP server
-|<<nng_http_server_stop.3http#,nng_http_server_stop()>>|stop HTTP server
+|xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc()]|allocate HTTP server handler
+|xref:nng_http_handler_collect_body.3http.adoc[nng_http_handler_collect_body()]|set HTTP handler to collect request body
+|xref:nng_http_handler_free.3http.adoc[nng_http_handler_free()]|free HTTP server handler
+|xref:nng_http_handler_get_data.3http.adoc[nng_http_handler_get_data()]|return extra data for HTTP handler
+|xref:nng_http_handler_set_data.3http.adoc[nng_http_handler_set_data()]|set extra data for HTTP handler
+|xref:nng_http_handler_set_host.3http.adoc[nng_http_handler_set_host()]|set host for HTTP handler
+|xref:nng_http_handler_set_method.3http.adoc[nng_http_handler_set_method()]|set HTTP handler method
+|xref:nng_http_handler_set_tree.3http.adoc[nng_http_handler_set_tree()]|set HTTP handler to match trees
+|xref:nng_http_hijack.3http.adoc[nng_http_hijack()]|hijack HTTP server connection
+|xref:nng_http_server_add_handler.3http.adoc[nng_http_server_add_handler()]|add HTTP server handler
+|xref:nng_http_server_del_handler.3http.adoc[nng_http_server_del_handler()]|delete HTTP server handler
+|xref:nng_http_server_get_tls.3http.adoc[nng_http_server_get_tls()]|get HTTP server TLS configuration
+|xref:nng_http_server_hold.3http.adoc[nng_http_server_hold()]|get and hold HTTP server instance
+|xref:nng_http_server_release.3http.adoc[nng_http_server_release()]|release HTTP server instance
+|xref:nng_http_server_set_error_file.3http.adoc[nng_http_server_set_error_file()]|set custom HTTP error file
+|xref:nng_http_server_set_error_page.3http.adoc[nng_http_server_set_error_page()]|set custom HTTP error page
+|xref:nng_http_server_set_tls.3http.adoc[nng_http_server_set_tls()]|set HTTP server TLS configuration
+|xref:nng_http_server_res_error.3http.adoc[nng_http_server_res_error()]|use HTTP server error page
+|xref:nng_http_server_start.3http.adoc[nng_http_server_start()]|start HTTP server
+|xref:nng_http_server_stop.3http.adoc[nng_http_server_stop()]|stop HTTP server
|===
=== TLS Configuration Objects
@@ -444,38 +422,38 @@ NOTE: These functions will only be present if the library has been built
with TLS support.
|===
-|<<nng_tls_close.3tls#,nng_tls_close()>>|close TLS connection
-|<<nng_tls_config_alloc.3tls#,nng_tls_config_alloc()>>|allocate TLS configuration
-|<<nng_tls_config_auth_mode.3tls#,nng_tls_config_auth_mode()>>|set authentication mode
-|<<nng_tls_config_ca_chain.3tls#,nng_tls_config_ca_chain()>>|set certificate authority chain
-|<<nng_tls_config_ca_file.3tls#,nng_tls_config_ca_file()>>|load certificate authority from file
-|<<nng_tls_config_cert_key_file.3tls#,nng_tls_config_cert_key_file()>>|load own certificate and key from file
-|<<nng_tls_config_own_cert.3tls#,nng_tls_config_own_cert()>>|set own certificate and key
-|<<nng_tls_config_free.3tls#,nng_tls_config_free()>>|free TLS configuration
-|<<nng_tls_config_server_name.3tls#,nng_tls_config_server_name()>>|set remote server name
-|<<nng_tls_dialer_alloc.3tls#,nng_tls_dialer_alloc()>>|allocate TLS dialer
-|<<nng_tls_dialer_close.3tls#,nng_tls_dialer_close()>>|close TLS dialer
-|<<nng_tls_dialer_dial.3tls#,nng_tls_dialer_dial()>>|initiate outgoing TLS connection
-|<<nng_tls_dialer_free.3tls#,nng_tls_dialer_free()>>|free TLS dialer
-|<<nng_tls_dialer_getopt.3tls#,nng_tls_dialer_getopt()>>|get option from TLS dialer
-|<<nng_tls_dialer_setopt.3tls#,nng_tls_dialer_setopt()>>|set option on TLS dialer
-|<<nng_tls_free.3tls#,nng_tls_free()>>|free TLS connection
-|<<nng_tls_getopt.3tls#,nng_tls_getopt()>>|get option from TLS connection
-|<<nng_tls_listener_accept.3tls#,nng_tls_listener_accept()>>|accept incoming TLS connection
-|<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc()>>|allocate TLS listener
-|<<nng_tls_listener_close.3tls#,nng_tls_listener_close()>>|close TLS listener
-|<<nng_tls_listener_free.3tls#,nng_tls_listener_free()>>|free TLS listener
-|<<nng_tls_listener_getopt.3tls#,nng_tls_listener_getopt()>>|get option from TLS listener
-|<<nng_tls_listener_listen.3tls#,nng_tls_listener_listen()>>|bind TLS listener to port
-|<<nng_tls_listener_setopt.3tls#,nng_tls_listener_setopt()>>|set option on TLS listener
-|<<nng_tls_recv.3tls#,nng_tls_recv()>>|receive from TLS connection
-|<<nng_tls_send.3tls#,nng_tls_send()>>|send to TLS connection
-|<<nng_tls_setopt.3tls#,nng_tls_setopt()>>|set option on TLS connection
+|xref:nng_tls_close.3tls.adoc[nng_tls_close()]|close TLS connection
+|xref:nng_tls_config_alloc.3tls.adoc[nng_tls_config_alloc()]|allocate TLS configuration
+|xref:nng_tls_config_auth_mode.3tls.adoc[nng_tls_config_auth_mode()]|set authentication mode
+|xref:nng_tls_config_ca_chain.3tls.adoc[nng_tls_config_ca_chain()]|set certificate authority chain
+|xref:nng_tls_config_ca_file.3tls.adoc[nng_tls_config_ca_file()]|load certificate authority from file
+|xref:nng_tls_config_cert_key_file.3tls.adoc[nng_tls_config_cert_key_file()]|load own certificate and key from file
+|xref:nng_tls_config_own_cert.3tls.adoc[nng_tls_config_own_cert()]|set own certificate and key
+|xref:nng_tls_config_free.3tls.adoc[nng_tls_config_free()]|free TLS configuration
+|xref:nng_tls_config_server_name.3tls.adoc[nng_tls_config_server_name()]|set remote server name
+|xref:nng_tls_dialer_alloc.3tls.adoc[nng_tls_dialer_alloc()]|allocate TLS dialer
+|xref:nng_tls_dialer_close.3tls.adoc[nng_tls_dialer_close()]|close TLS dialer
+|xref:nng_tls_dialer_dial.3tls.adoc[nng_tls_dialer_dial()]|initiate outgoing TLS connection
+|xref:nng_tls_dialer_free.3tls.adoc[nng_tls_dialer_free()]|free TLS dialer
+|xref:nng_tls_dialer_getopt.3tls.adoc[nng_tls_dialer_getopt()]|get option from TLS dialer
+|xref:nng_tls_dialer_setopt.3tls.adoc[nng_tls_dialer_setopt()]|set option on TLS dialer
+|xref:nng_tls_free.3tls.adoc[nng_tls_free()]|free TLS connection
+|xref:nng_tls_getopt.3tls.adoc[nng_tls_getopt()]|get option from TLS connection
+|xref:nng_tls_listener_accept.3tls.adoc[nng_tls_listener_accept()]|accept incoming TLS connection
+|xref:nng_tls_listener_alloc.3tls.adoc[nng_tls_listener_alloc()]|allocate TLS listener
+|xref:nng_tls_listener_close.3tls.adoc[nng_tls_listener_close()]|close TLS listener
+|xref:nng_tls_listener_free.3tls.adoc[nng_tls_listener_free()]|free TLS listener
+|xref:nng_tls_listener_getopt.3tls.adoc[nng_tls_listener_getopt()]|get option from TLS listener
+|xref:nng_tls_listener_listen.3tls.adoc[nng_tls_listener_listen()]|bind TLS listener to port
+|xref:nng_tls_listener_setopt.3tls.adoc[nng_tls_listener_setopt()]|set option on TLS listener
+|xref:nng_tls_recv.3tls.adoc[nng_tls_recv()]|receive from TLS connection
+|xref:nng_tls_send.3tls.adoc[nng_tls_send()]|send to TLS connection
+|xref:nng_tls_setopt.3tls.adoc[nng_tls_setopt()]|set option on TLS connection
|===
== SEE ALSO
[.text-left]
-<<nng_compat.3compat#,nng_compat(3compat)>>,
-<<nng.7#,nng(7)>>
+xref:nng_compat.3compat.adoc[nng_compat(3compat)],
+xref:nng.7.adoc[nng(7)]
diff --git a/docs/man/man3ipc.desc b/docs/man/man3ipc.desc
deleted file mode 100644
index c38f257e..00000000
--- a/docs/man/man3ipc.desc
+++ /dev/null
@@ -1,5 +0,0 @@
-This section documents supplemental TCP functions that are available.
-
-These functions are made available to facilitate using raw TCP connections
-with the NNG asynchronous I/O API.
-Most applications should never need to use these functions.
diff --git a/docs/man/man3str.desc b/docs/man/man3str.desc
new file mode 100644
index 00000000..e1fe5f9e
--- /dev/null
+++ b/docs/man/man3str.desc
@@ -0,0 +1,7 @@
+This section documents supplemental byte stream functions that
+are available.
+
+These functions are made available to facilitate using raw byte stream
+connections with the NNG asynchronous I/O API.
+These byte streams may be useful for applications that need to
+communicate with raw TCP/IP or IPC streams instead of Scalability Protocols.
diff --git a/docs/man/man3ipc.sect b/docs/man/man3str.sect
index ed1b8306..ed1b8306 100644
--- a/docs/man/man3ipc.sect
+++ b/docs/man/man3str.sect
diff --git a/docs/man/nng_getopt.3.adoc b/docs/man/nng_getopt.3.adoc
index 06d6ac19..491d6038 100644
--- a/docs/man/nng_getopt.3.adoc
+++ b/docs/man/nng_getopt.3.adoc
@@ -59,25 +59,25 @@ on the actual option, and will be documented with the option itself.
This function is untyped and can be used to retrieve the value of any option.
The caller must store a pointer to a buffer to receive the value in _val_,
and the size of the buffer shall be stored at the location referenced by
-_valszp_. +
- +
+_valszp_.
++
When the function returns, the actual size of the data copied (or that
would have been copied if sufficient space were present) is stored at
the location referenced by _valszp_.
If the caller's buffer is not large enough to hold the entire object,
then the copy is truncated.
Therefore the caller should check for truncation by verifying that the
-returned size in _valszp_ does not exceed the original buffer size. +
- +
+returned size in _valszp_ does not exceed the original buffer size.
++
It is acceptable to pass `NULL` for _val_ if the value in _valszp_ is zero.
This can be used to determine the size of the buffer needed to receive
the object.
-
++
TIP: It may be easier to use one of the typed forms of this function.
`nng_getopt_bool()`::
This function is for options which take a Boolean (`bool`).
-The value will be stored at _ivalp_.
+The value will be stored at _bvalp_.
`nng_getopt_int()`::
This function is for options which take an integer (`int`).
diff --git a/docs/man/nng_ipc.5.adoc b/docs/man/nng_ipc.5.adoc
deleted file mode 100644
index 93a131e0..00000000
--- a/docs/man/nng_ipc.5.adoc
+++ /dev/null
@@ -1,87 +0,0 @@
-= nng_ipc(5)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc - IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-typedef struct nng_ipc_s nng_ipc;
-----
-
-== DESCRIPTION
-
-An `nng_ipc` (((IPC connection))) represents a connected stream
-using interprocess communication (IPC).
-IPC stream objects can be used to send or receive data.
-
-NOTE: The `nng_ipc` object is used for raw IPC connections, and
-should not be confused with a pipe object created using the
-<<nng_ipc.7#,nng_ipc(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_ipc.7#,nng_ipc(7)>> transport instead.
-
-These objects are created either establishing an outgoing connection
-with <<nng_ipc_dialer_dial.3ipc#,`nng_ipc_dialer_dial()`>> or by
-accepting in incoming connection with
-<<nng_ipc_listener_accept.3ipc#,`nng_ipc_listener_accept()`>>.
-
-IPC connections are byte streams, and are "`reliable`" in that data
-will not be delivered out of order, or with portions missing.
-
-Data can be sent using <<nng_ipc_send.3ipc#,`nng_ipc_send()`>> or
-received with <<nng_ipc_recv.3ipc#,`nng_ipc_recv()`>>.
-
-When the connection is no longer needed, it should be freed with
-<<nng_ipc_free.3ipc#,`nng_ipc_free()`>>.
-
-TIP: It is possible to close the connection, without freeing it, by
-using <<nng_ipc_close.3ipc#,`nng_ipc_close()`>>.
-
-=== Options
-
-The following options are applicable to IPC connections, and may be
-accessed using the <<nng_ipc_getopt.3ipc#,`nng_ipc_getopt()`>> and
-<<nng_ipc_setopt.3ipc#,`nng_ipc_setopt()`>> functions.
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_GID,`NNG_OPT_IPC_PEER_GID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_PID,`NNG_OPT_IPC_PEER_PID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_UID,`NNG_OPT_IPC_PEER_UID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_ZONEID,`NNG_OPT_IPC_PEER_ZONEID`>>
-
-Other platform specific options may be available as well.
-
-== SEE ALSO
-
-[.text-left]
-<<libnng.3#,libnng(3)>>,
-<<nng_ipc_close.3ipc#,nng_ipc_close(3ipc)>>,
-<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial(3ipc)>>,
-<<nng_ipc_free.3ipc#,nng_ipc_free(3ipc)>>,
-<<nng_ipc_getopt.3ipc#,nng_ipc_getopt(3ipc)>>,
-<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept(3ipc)>>,
-<<nng_ipc_recv.3ipc#,nng_ipc_recv(3ipc)>>,
-<<nng_ipc_send.3ipc#,nng_ipc_send(3ipc)>>,
-<<nng_ipc_setopt.3ipc#,nng_ipc_setopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng.7#,nng(7)>>,
-<<nng_ipc.7#,nng_ipc(7)>>
diff --git a/docs/man/nng_ipc_close.3ipc.adoc b/docs/man/nng_ipc_close.3ipc.adoc
deleted file mode 100644
index df490013..00000000
--- a/docs/man/nng_ipc_close.3ipc.adoc
+++ /dev/null
@@ -1,61 +0,0 @@
-= nng_ipc_close(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_close - close IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_close(nng_ipc *conn);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_close()` function closes the supplied IPC connection, _conn_.
-
-If any operations are pending (such as <<nng_ipc_send.3ipc#,`nng_ipc_send()`>>
-or <<nng_ipc_recv.3ipc#,`nng_ipc_recv()`>>) they will be terminated with
-an `NNG_ECLOSED` error condition.
-Also, any new operations will fail with `NNG_ECLOSED` after the connection
-is closed.
-
-NOTE: Closing the connection while data is in transmission will likely
-lead to loss of that data.
-There is no automatic linger or flush to ensure that the socket send buffers
-have completely transmitted.
-
-NOTE: Closing the connection does not free the resources associated with it.
-Once it is certain that no more operations are pending on the connection,
-it should be freed with <<nng_ipc_free.3ipc#,`nng_ipc_free()`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_free.3ipc#,nng_ipc_free(3ipc)>>,
-<<nng_ipc_recv.3ipc#,nng_ipc_recv(3ipc)>>,
-<<nng_ipc_send.3ipc#,nng_ipc_send(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>
diff --git a/docs/man/nng_ipc_dialer.5.adoc b/docs/man/nng_ipc_dialer.5.adoc
deleted file mode 100644
index 23eb1c55..00000000
--- a/docs/man/nng_ipc_dialer.5.adoc
+++ /dev/null
@@ -1,51 +0,0 @@
-= nng_ipc_dialer(5)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer - IPC dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-typedef struct nng_ipc_dialer_s nng_ipc_dialer;
-----
-
-== DESCRIPTION
-
-(((IPC, dialer)))
-An `nng_ipc_dialer` is a handle to an IPC "`dialer`", which is responsible for
-creating connections (<<nng_ipc.5#,`nng_ipc`>> objects) by connecting to
-remote systems.
-
-NOTE: The `nng_ipc_dialer` object is used for raw IPC connections, and
-should not be confused with a dialer object created using the
-<<nng_ipc.7#,nng_ipc(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_ipc.7#,nng_ipc(7)>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_dialer_alloc.3ipc#,nng_ipc_dialer_alloc(3ipc)>>,
-<<nng_ipc_dialer_close.3ipc#,nng_ipc_dialer_close(3ipc)>>,
-<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial(3ipc)>>,
-<<nng_ipc_dialer_free.3ipc#,nng_ipc_dialer_free(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>,
-<<nng_ipc.7#,nng_ipc(7)>>
diff --git a/docs/man/nng_ipc_dialer_alloc.3ipc.adoc b/docs/man/nng_ipc_dialer_alloc.3ipc.adoc
deleted file mode 100644
index 6b2c1fbb..00000000
--- a/docs/man/nng_ipc_dialer_alloc.3ipc.adoc
+++ /dev/null
@@ -1,49 +0,0 @@
-= nng_ipc_dialer_alloc(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer_alloc - allocate IPC dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_dialer_alloc(nng_ipc_dialer *dp);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_dialer_alloc()` allocates an IPC dialer, which can be used
-to create outgoing connections over IPC, and stores a pointer to it
-it in the location referenced by _dp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_dialer_close.3ipc#,nng_ipc_dialer_close(3ipc)>>,
-<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial(3ipc)>>,
-<<nng_ipc_dialer_free.3ipc#,nng_ipc_dialer_free(3ipc)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_ipc_dialer_close.3ipc.adoc b/docs/man/nng_ipc_dialer_close.3ipc.adoc
deleted file mode 100644
index 013274eb..00000000
--- a/docs/man/nng_ipc_dialer_close.3ipc.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-= nng_ipc_dialer_close(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer_close - close IPC dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_dialer_close(nng_ipc_dialer *d);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_dialer_close()` function closes the supplied IPC dialer _d_,
-but does not free the underlying resources associated with it.
-
-If any <<nng_ipc_dialer_dial.3ipc#,dial>> operations using _d_ are
-in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-Furthermore any future accesses to the dialer _d_ will also result in
-`NNG_ECLOSED`.
-
-NOTE: This function does not release the memory for the dialer, so the
-application should still free the memory using
-<<nng_ipc_dialer_free.3ipc#,`nng_ipc_dialer_free(3ipc)`>>
-once it is certain that nothing else is using it.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_dialer_alloc.3ipc#,nng_ipc_dialer_alloc(3ipc)>>,
-<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial(3ipc)>>,
-<<nng_ipc_dialer_free.3ipc#,nng_ipc_dialer_free(3ipc)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>
diff --git a/docs/man/nng_ipc_dialer_dial.3ipc.adoc b/docs/man/nng_ipc_dialer_dial.3ipc.adoc
deleted file mode 100644
index 09d4dc02..00000000
--- a/docs/man/nng_ipc_dialer_dial.3ipc.adoc
+++ /dev/null
@@ -1,65 +0,0 @@
-= nng_ipc_dialer_dial(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer_dial - initiate outgoing IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_dialer_dial(nng_ipc_dialer *d, const nng_sockaddr *sa, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_dialer_dial()` attempts to establish an IPC connection to the
-remote peer identified by _sa_, using the dialer _d_.
-The operation is completed asynchronously, using _aio_.
-
-The address _sa_ must be in the `NNG_AF_IPC` family,
-and have a valid path for IPC.
-
-If a connection is successfully established, the _aio_ will have the
-resulting <<nng_ipc.5#,`nng_ipc`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_EADDRINVAL`:: The address specified is invalid.
-`NNG_ECANCELED`:: The operation was aborted.
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_ECONNREFUSED`:: The connection was refused by the server.
-`NNG_ECONNRESET`:: The connection was reset by the server.
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_EPERM`:: Insufficient permission to access the IPC path.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_dialer_alloc.3ipc#,nng_ipc_dialer_alloc(3ipc)>>,
-<<nng_ipc_dialer_close.3ipc#,nng_ipc_dialer_close(3ipc)>>,
-<<nng_ipc_dialer_free.3ipc#,nng_ipc_dialer_free(3ipc)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>
diff --git a/docs/man/nng_ipc_dialer_getopt.3ipc.adoc b/docs/man/nng_ipc_dialer_getopt.3ipc.adoc
deleted file mode 100644
index 4a480bb5..00000000
--- a/docs/man/nng_ipc_dialer_getopt.3ipc.adoc
+++ /dev/null
@@ -1,64 +0,0 @@
-= nng_ipc_dialer_getopt(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer_getopt - get option from IPC dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_getopt(nng_ipc_dialer *d, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_dialer_getopt()` is used to retrieve the value of the option _name_ for the <<nng_ipc_dialer.5#,IPC dialer>> _d_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-There are no predefined options for IPC dialers at this time.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_dialer_setopt.3ipc#,nng_ipc_dialer_setopt(3ipc)>>,
-<<nng_ipc_getopt.3ipc#,nng_ipc_getopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>
diff --git a/docs/man/nng_ipc_dialer_setopt.3ipc.adoc b/docs/man/nng_ipc_dialer_setopt.3ipc.adoc
deleted file mode 100644
index 03f45023..00000000
--- a/docs/man/nng_ipc_dialer_setopt.3ipc.adoc
+++ /dev/null
@@ -1,59 +0,0 @@
-= nng_ipc_dialer_setopt(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_dialer_setopt - set option on IPC dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_dialer_setopt(nng_ipc_dialer *d, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_dialer_setopt()` is used to set the option _name_ for the
-<<nng_ipc_dialer.5#,IPC dialer>> _d_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-There are no predefined options for IPC dialers at this time.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_dialer_getopt.3ipc#,nng_ipc_dialer_getopt(3ipc)>>,
-<<nng_ipc_setopt.3ipc#,nng_ipc_setopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>
diff --git a/docs/man/nng_ipc_free.3ipc.adoc b/docs/man/nng_ipc_free.3ipc.adoc
deleted file mode 100644
index 646122a0..00000000
--- a/docs/man/nng_ipc_free.3ipc.adoc
+++ /dev/null
@@ -1,59 +0,0 @@
-= nng_ipc_free(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_free - free IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_free(nng_ipc *conn);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_free()` function closes the supplied IPC connection, _conn_,
-and frees the underlying resources associated with it.
-
-If any operations are pending (such as <<nng_ipc_send.3ipc#,`nng_ipc_send()`>>
-or <<nng_ipc_recv.3ipc#,`nng_ipc_recv()`>>) they will be terminated with
-an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _conn_, as the memory backing it will be reclaimed for other uses.
-
-NOTE: Closing the connection while data is in transmission will likely
-lead to loss of that data.
-There is no automatic linger or flush to ensure that the socket send buffers
-have completely transmitted.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_close.3ipc#,nng_ipc_close(3ipc)>>,
-<<nng_ipc_recv.3ipc#,nng_ipc_recv(3ipc)>>,
-<<nng_ipc_send.3ipc#,nng_ipc_send(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>
diff --git a/docs/man/nng_ipc_getopt.3ipc.adoc b/docs/man/nng_ipc_getopt.3ipc.adoc
deleted file mode 100644
index d197e93e..00000000
--- a/docs/man/nng_ipc_getopt.3ipc.adoc
+++ /dev/null
@@ -1,70 +0,0 @@
-= nng_ipc_getopt(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_getopt - get option from IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_getopt(nng_ipc *conn, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_getopt()` is used to retrieve the value of the option _name_ for
-the <<nng_ipc.5#,IPC connection>> _conn_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from IPC connections are:
-
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_GID,`NNG_OPT_IPC_PEER_GID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_PID,`NNG_OPT_IPC_PEER_PID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_UID,`NNG_OPT_IPC_PEER_UID`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_PEER_ZONEID,`NNG_OPT_IPC_PEER_ZONEID`>>
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_setopt.3ipc#,nng_ipc_setopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>
diff --git a/docs/man/nng_ipc_listener.5.adoc b/docs/man/nng_ipc_listener.5.adoc
deleted file mode 100644
index 1d748efc..00000000
--- a/docs/man/nng_ipc_listener.5.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_ipc_listener(5)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener - IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-typedef struct nng_ipc_dialer_s nng_ipc_dialer;
-----
-
-== DESCRIPTION
-
-(((IPC, listener)))
-An `nng_ipc_listener` is a handle to an IPC "`listener`", which is responsible
-for accepting connections (<<nng_ipc.5#,`nng_ipc`>> objects) from remote
-systems.
-
-NOTE: The `nng_ipc_listener` object is used for raw IPC connections, and
-should not be confused with a listener object created using the
-<<nng_ipc.7#,nng_ipc(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_ipc.7#,nng_ipc(7)>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept(3ipc)>>,
-<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc(3ipc)>>,
-<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close(3ipc)>>,
-<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free(3ipc)>>,
-<<nng_ipc_listener_listen.3ipc#,nng_ipc_listener_listen(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_ipc.7#,nng_ipc(7)>>
diff --git a/docs/man/nng_ipc_listener_accept.3ipc.adoc b/docs/man/nng_ipc_listener_accept.3ipc.adoc
deleted file mode 100644
index 573539a8..00000000
--- a/docs/man/nng_ipc_listener_accept.3ipc.adoc
+++ /dev/null
@@ -1,63 +0,0 @@
-= nng_ipc_listener_accept(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_accept - accept incoming IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_listener_accept(nng_ipc_listener *l, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_accept()` attempts to accept an incoming IPC connection
-from a remote peer, using the listener _l_.
-The operation is completed asynchronously, using _aio_.
-
-This operation can only be done after the listener is already bound to
-an IPC path and is <<nng_ipc_listener_listen.3ipc#,listening>>.
-
-If a connection is successfully established, the _aio_ will have the
-resulting <<nng_ipc.5#,`nng_ipc`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was aborted.
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_ECONNRESET`:: The connection was reset by the peer.
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_ESTATE`:: The listener is not not listening.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc(3ipc)>>,
-<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close(3ipc)>>,
-<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free(3ipc)>>,
-<<nng_ipc_listener_listen.3ipc#,nng_ipc_listener_listen(3ipc)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_listener_alloc.3ipc.adoc b/docs/man/nng_ipc_listener_alloc.3ipc.adoc
deleted file mode 100644
index b9372bb7..00000000
--- a/docs/man/nng_ipc_listener_alloc.3ipc.adoc
+++ /dev/null
@@ -1,50 +0,0 @@
-= nng_ipc_listener_alloc(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_alloc - allocate IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_listener_alloc(nng_ipc_listener *lp);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_alloc()` allocates an IPC listener, which can be used
-to accept incoming connections over IPC, and stores a pointer to it
-it in the location referenced by _lp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept(3ipc)>>,
-<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close(3ipc)>>,
-<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free(3ipc)>>,
-<<nng_ipc_listener_listen.3ipc#,nng_ipc_listener_listen(3ipc)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_ipc_listener_close.3ipc.adoc b/docs/man/nng_ipc_listener_close.3ipc.adoc
deleted file mode 100644
index 8e27abde..00000000
--- a/docs/man/nng_ipc_listener_close.3ipc.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-= nng_ipc_listener_close(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_close - close IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_listener_close(nng_ipc_listener *l);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_close()` function closes the supplied IPC listener _l_,
-but does not free the underlying resources associated with it.
-
-If any <<nng_ipc_listener_accept.3ipc#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-Furthermore any future accesses to the listener _l_ will also result in
-`NNG_ECLOSED`.
-
-NOTE: This function does not release the memory for the listener, so the
-application should still free the memory using
-<<nng_ipc_listener_free.3ipc#,`nng_ipc_listener_free()`>>
-once it is certain that nothing else is using it.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc(3ipc)>>,
-<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept(3ipc)>>,
-<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free(3ipc)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_listener_free.3ipc.adoc b/docs/man/nng_ipc_listener_free.3ipc.adoc
deleted file mode 100644
index a90bcca5..00000000
--- a/docs/man/nng_ipc_listener_free.3ipc.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_ipc_listener_free(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_free - free IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_listener_free(nng_ipc_listener *l);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_free()` function closes the supplied IPC listener _l_,
-and frees the underlying resources associated with it.
-
-If any <<nng_ipc_listener_accept.3ipc#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _l_, as the memory backing it will be reclaimed for other uses.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc(3ipc)>>,
-<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close(3ipc)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_listener_getopt.3ipc.adoc b/docs/man/nng_ipc_listener_getopt.3ipc.adoc
deleted file mode 100644
index f5e47ede..00000000
--- a/docs/man/nng_ipc_listener_getopt.3ipc.adoc
+++ /dev/null
@@ -1,66 +0,0 @@
-= nng_ipc_listener_getopt(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_getopt - get option from IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_listener_getopt(nng_ipc_listener *l, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_getopt()` is used to retrieve the value of the option _name_ for the <<nng_ipc_listener.5#,IPC listener>> _l_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The only option specifically suppported for retrieval from IPC listeners is:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_listener_setopt.3ipc#,nng_ipc_listener_setopt(3ipc)>>,
-<<nng_ipc_getopt.3ipc#,nng_ipc_getopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_listener_listen.3ipc.adoc b/docs/man/nng_ipc_listener_listen.3ipc.adoc
deleted file mode 100644
index 43b29c9b..00000000
--- a/docs/man/nng_ipc_listener_listen.3ipc.adoc
+++ /dev/null
@@ -1,56 +0,0 @@
-= nng_ipc_listener_listen(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_listen - bind IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_listener_listen(nng_ipc_listener l, const nng_sockaddr *sa);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_listen()` attempts to bind the listener _l_
-to the local address specified by _sa_, which must be in the
-`NNG_AF_IPC` address family and must have a valid IPC path.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_EADDRINUSE`:: The address specified by _sa_ is already in use.
-`NNG_EADDRINVAL`:: The address specified by _sa_ is invalid or unavailable.
-`NNG_ECLOSED`:: The listener _l_ has been closed.
-`NNG_EPERM`:: Insufficient permission to create the specified IPC path.
-`NNG_ESTATE`:: The listener _l_ is already bound.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_listener_accept.3ipc#,nng_ipc_listener_accept(3ipc)>>,
-<<nng_ipc_listener_alloc.3ipc#,nng_ipc_listener_alloc(3ipc)>>,
-<<nng_ipc_listener_close.3ipc#,nng_ipc_listener_close(3ipc)>>,
-<<nng_ipc_listener_free.3ipc#,nng_ipc_listener_free(3ipc)>>,
-<<nng_ipc_listener_getopt.3ipc#,nng_ipc_listener_getopt(3ipc)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_listener_setopt.3ipc.adoc b/docs/man/nng_ipc_listener_setopt.3ipc.adoc
deleted file mode 100644
index 0f627eab..00000000
--- a/docs/man/nng_ipc_listener_setopt.3ipc.adoc
+++ /dev/null
@@ -1,64 +0,0 @@
-= nng_ipc_listener_setopt(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_listener_setopt - set option on IPC listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_listener_setopt(nng_ipc_listener *l, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_listener_setopt()` is used to set the option _name_ for the
-<<nng_ipc_listener.5#,IPC listener>> _l_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on IPC listeners are:
-
-* <<nng_ipc_options.5#NNG_OPT_IPC_PERMISSIONS,`NNG_OPT_IPC_PERMISSIONS`>>
-* <<nng_ipc_options.5#NNG_OPT_IPC_SECURITY_DESCRIPTOR,`NNG_OPT_IPC_SECURITY_DESCRIPTOR`>>
-
-NOTE: Availability of the above options is platform-specific.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_listener_getopt.3ipc#,nng_ipc_listener_getopt(3ipc)>>,
-<<nng_ipc_setopt.3ipc#,nng_ipc_setopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_ipc_listener.5#,nng_ipc_listener(5)>>
diff --git a/docs/man/nng_ipc_recv.3ipc.adoc b/docs/man/nng_ipc_recv.3ipc.adoc
deleted file mode 100644
index 44ed8651..00000000
--- a/docs/man/nng_ipc_recv.3ipc.adoc
+++ /dev/null
@@ -1,72 +0,0 @@
-= nng_ipc_recv(3ipc)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_recv - receive from IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-void nng_ipc_recv(nng_ipc *conn, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_recv()` function starts an asynchronous receive from the
-IPC connection _conn_, into the scatter/gather vector located in the
-asynchronous I/O structure _aio_.
-
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
-called first, to set the scatter/gather vector for _aio_.
-
-This function returns immediately, with no return value.
-Completion of the operation is signaled via the _aio_,
-and the final result may be obtained via
-<<nng_aio_result.3#,`nng_aio_result()`>>.
-That result will either be zero or an error code.
-
-The I/O operation completes as soon as at least one byte has been
-received, or an error has occurred.
-Therefore, the number of bytes read may be less than requested.
-The actual number of bytes read can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was canceled.
-`NNG_ECLOSED`:: The connection was closed.
-`NNG_ECONNRESET`:: The peer closed the connection.
-`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector.
-`NNG_ENOMEM`:: Insufficient free memory to perform the operation.
-`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_ipc_close.3ipc#,nng_ipc_close(3ipc)>>,
-<<nng_ipc_send.3ipc#,nng_ipc_send(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_ipc_setopt.3ipc.adoc b/docs/man/nng_ipc_setopt.3ipc.adoc
deleted file mode 100644
index b22bda98..00000000
--- a/docs/man/nng_ipc_setopt.3ipc.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-= nng_ipc_setopt(3ipc)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_ipc_setopt - set option on IPC connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-
-int nng_ipc_setopt(nng_ipc *conn, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_ipc_setopt()` is used to set the option _name_ for the
-<<nng_ipc.5#,IPC connection>> _conn_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-There are no options defined for modification on IPC connections at this time.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_ipc_getopt.3ipc#,nng_ipc_getopt(3ipc)>>,
-<<nng_ipc_options.5#,nng_ipc_options(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc.5#,nng_ipc(5)>>
diff --git a/docs/man/nng_stream.5.adoc b/docs/man/nng_stream.5.adoc
new file mode 100644
index 00000000..3e815da4
--- /dev/null
+++ b/docs/man/nng_stream.5.adoc
@@ -0,0 +1,80 @@
+= nng_stream(5)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream - byte stream
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+typedef struct nng_stream nng_stream;
+----
+
+== DESCRIPTION
+
+An `nng_stream` (((byte stream))) represents a byte stream.
+This may correspond to an underlying connection such a TCP connection or
+a connected UNIX domain socket or named pipe.
+
+NOTE: The `nng_stream` object is used for raw byte stream connections, and
+should not be confused with a pipe object created on
+xref:nng_socket.5.adoc[socket] using the
+xref:nng_listen.3.adoc[`nng_listen()`],
+xref:nng_dial.3.adoc[`nng_dial()`] or related functions.
+
+These objects are created either establishing an outgoing connection
+with
+xref:nng_stream_dialer_dial.3str.adoc[`nng_stream_dialer_dial()`]
+or by accepting in incoming connection with
+xref:nng_stream_listener_accept.3str.adoc[`nng_stream_listener_accept()`].
+
+Byte streams are "`reliable`" in that data
+will not be delivered out of order, or with portions missing.
+
+Data can be sent using
+xref:nng_stream_send.3str.adoc[`nng_stream_send()`] or
+received with
+xref:nng_stream_recv.3str.adoc[`nng_stream_recv()`].
+
+When the connection is no longer needed, it should be freed with
+xref:nng_stream_free.3str.adoc[`nng_stream_free()`].
+
+TIP: It is possible to close the connection, without freeing it, by
+using
+xref:nng_stream_close.3str.adoc[`nng_stream_close()`].
+
+Byte streams may, depending on the underlying technology,
+support various
+xref:nng_options.5.adoc[options], which
+can be accessed using the
+xref:nng_stream_get.3str.adoc[`nng_stream_get()`] and
+xref:nng_stream_set.3str.adoc[`nng_stream_set()`] family of
+functions.
+
+== SEE ALSO
+
+[.text-left]
+xref:libnng.3.adoc[libnng(3)],
+xref:nng_stream_close.3str.adoc[nng_stream_close(3str)],
+xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial(3str)],
+xref:nng_stream_free.3str.adoc[nng_stream_free(3str)],
+xref:nng_stream_getopt.3str.adoc[nng_stream_getopt(3str)],
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)],
+xref:nng_stream_recv.3str.adoc[nng_stream_recv(3str)],
+xref:nng_stream_send.3str.adoc[nng_stream_send(3str)],
+xref:nng_stream_setopt.3str.adoc[nng_stream_setopt(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng.7.adoc[nng(7)],
diff --git a/docs/man/nng_tls_close.3tls.adoc b/docs/man/nng_stream_close.3str.adoc
index 49836965..9e7b8d6a 100644
--- a/docs/man/nng_tls_close.3tls.adoc
+++ b/docs/man/nng_stream_close.3str.adoc
@@ -1,4 +1,4 @@
-= nng_tls_close(3tls)
+= nng_stream_close(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
@@ -12,24 +12,27 @@
== NAME
-nng_tls_close - close TLS connection
+nng_stream_close - close byte stream
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_close(nng_tls *conn);
+void nng_stream_close(nng_stream *s);
----
== DESCRIPTION
-The `nng_tls_close()` function closes the supplied TLS connection, _conn_.
+The `nng_stream_close()` function closes the
+xref:nng_stream.5.adoc[byte stream] _s_.
-If any operations are pending (such as <<nng_tls_send.3tls#,`nng_tls_send()`>>
-or <<nng_tls_recv.3tls#,`nng_tls_recv()`>> they will be terminated with
+If any operations are pending, such as
+xref:nng_stream_send.3str.adoc[`nng_stream_send()`]
+or
+xref:nng_stream_recv.3str.adoc[`nng_stream_recv()`],
+they will be terminated with
an `NNG_ECLOSED` error condition.
Also, any new operations will fail with `NNG_ECLOSED` after the connection
is closed.
@@ -41,7 +44,8 @@ have completely transmitted.
NOTE: Closing the connection does not free the resources associated with it.
Once it is certain that no more operations are pending on the connection,
-it should be freed with <<nng_tls_free.3tls#,`nng_tls_free()`>>.
+it should be freed with
+xref:nng_stream_free.3str.adoc[`nng_stream_free()`].
== RETURN VALUES
@@ -54,8 +58,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_free.3tls#,nng_tls_free(3tls)>>,
-<<nng_tls_recv.3tls#,nng_tls_recv(3tls)>>,
-<<nng_tls_send.3tls#,nng_tls_send(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_free.3str.adoc[nng_stream_free(3str)],
+xref:nng_stream_recv.3str.adoc[nng_stream_recv(3str)],
+xref:nng_stream_send.3str.adoc[nng_stream_send(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)]
diff --git a/docs/man/nng_stream_dialer.5.adoc b/docs/man/nng_stream_dialer.5.adoc
new file mode 100644
index 00000000..5c1d2e0b
--- /dev/null
+++ b/docs/man/nng_stream_dialer.5.adoc
@@ -0,0 +1,46 @@
+= nng_stream_dialer(5)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_dialer - byte stream dialer
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+typedef struct nng_stream_dialer nng_stream_dialer;
+----
+
+== DESCRIPTION
+
+(((byte stream, dialer)))
+An `nng_stream_dialer` is a handle to a "`dialer`" for byte streams,
+and is responsible for creating
+xref:nng_stream.5.adoc[`nng_stream`] objects (corresponding to connected byte
+streams) by connecting to remote peers.
+
+NOTE: The `nng_stream_dialer` object is used for low-level byte stream
+connections, and should not be confused with a high-level
+xref:nng_dialer.5.adoc[`nng_dialer`] object.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc(3str)],
+xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close(3str)],
+xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial(3str)],
+xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_stream_dialer_alloc.3str.adoc b/docs/man/nng_stream_dialer_alloc.3str.adoc
new file mode 100644
index 00000000..0c2db67c
--- /dev/null
+++ b/docs/man/nng_stream_dialer_alloc.3str.adoc
@@ -0,0 +1,68 @@
+= nng_stream_dialer_alloc(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_dialer_alloc - allocate byte stream dialer
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_dialer_alloc(nng_stream_dialer **dp, const char *addr);
+
+int nng_stream_dialer_alloc_url(nng_stream_dialer **dp, const nng_url *url);
+----
+
+== DESCRIPTION
+
+These functions allocates a dialer for byte streams.
+Dialers create
+xref:nng_stream.5.adoc[`nng_stream`] objects by initiating outgoing
+connections, via the
+xref:nng_stream_dialer_dial.3str.adoc[`nng_stream_dialer_dial()`] function.
+
+The first form, `nng_stream_dialer_alloc()`, connects to the address
+specified by _addr_, which should be a string representing a URL.
+
+The second form, `nng_stream_dialer_alloc_url()`, takes a pre-parsed
+or pre-constructed
+xref:nng_url.5.adoc[`nng_url`] object to determine the remote address.
+
+These functions may support different URL schemes, such as
+`ipc://`, `tcp://`, `tls+tcp://`, or `ws://`.
+
+Both forms store the dialer in the location referenced by _dp_.
+
+== RETURN VALUES
+
+These functions return 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ENOMEM`:: Insufficient free memory exists.
+`NNG_ENOTSUP`:: The URL scheme is not supported by the implementation.
+`NNG_EADDRINVAL`:: The URL requested is invalid.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close(3str)]
+xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial(3str)]
+xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free(3str)]
+xref:nng_stream_dialer_get.3str.adoc[nng_stream_dialer_get(3str)]
+xref:nng_stream_dialer_set.3str.adoc[nng_stream_dialer_set(3str)]
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_tls_dialer_close.3tls.adoc b/docs/man/nng_stream_dialer_close.3str.adoc
index 19ca0bd1..59d9dec0 100644
--- a/docs/man/nng_tls_dialer_close.3tls.adoc
+++ b/docs/man/nng_stream_dialer_close.3str.adoc
@@ -1,6 +1,6 @@
-= nng_tls_dialer_close(3tls)
+= nng_stream_dialer_close(3str)
//
-// 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,24 +12,26 @@
== NAME
-nng_tls_dialer_close - close TLS dialer
+nng_stream_dialer_close - close byte stream dialer
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_dialer_close(nng_tls_dialer *d);
+void nng_stream_dialer_close(nng_stream_dialer *d);
----
== DESCRIPTION
-The `nng_tls_dialer_close()` function closes the supplied TCP dialer _d_,
+The `nng_stream_dialer_close()` function closes the supplied byte stream
+dialer _d_,
but does not free the underlying resources associated with it.
-If any <<nng_tls_dialer_dial.3tls#,dial>> operations using _d_ are
+If any
+xref:nng_stream_dialer_dial.3str.adoc[dial]
+operations using _d_ are
in progress, they will be terminated with an `NNG_ECLOSED` error condition.
Furthermore any future accesses to the dialer _d_ will also result in
@@ -37,7 +39,7 @@ Furthermore any future accesses to the dialer _d_ will also result in
NOTE: This function does not release the memory for the dialer, so the
application should still free the memory using
-<<nng_tls_dialer_free.3tls#,`nng_tls_dialer_free()`>>
+xref:nng_stream_dialer_free.3str.adoc[`nng_stream_dialer_free()`]
once it is certain that nothing else is using it.
== RETURN VALUES
@@ -51,8 +53,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_alloc.3tls#,nng_tls_dialer_alloc(3tls)>>,
-<<nng_tls_dialer_dial.3tls#,nng_tls_dialer_dial(3tls)>>,
-<<nng_tls_dialer_free.3tls#,nng_tls_dialer_free(3tls)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc(3str)],
+xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial(3str)],
+xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free(3str)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_tls_dialer_dial.3tls.adoc b/docs/man/nng_stream_dialer_dial.3str.adoc
index 31d9036d..cc4c55de 100644
--- a/docs/man/nng_tls_dialer_dial.3tls.adoc
+++ b/docs/man/nng_stream_dialer_dial.3str.adoc
@@ -1,4 +1,4 @@
-= nng_tls_dialer_dial(3tls)
+= nng_stream_dialer_dial(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
@@ -12,30 +12,32 @@
== NAME
-nng_tls_dialer_dial - initiate outgoing TLS connection
+nng_stream_dialer_dial - initiate outgoing byte stream connection
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_dialer_dial(nng_tls_dialer *d, const nng_sockaddr *sa, nng_aio *aio);
+void nng_stream_dialer_dial(nng_stream_dialer *d, nng_aio *aio);
----
== DESCRIPTION
-The `nng_tls_dialer_dial()` attempts to establish a TLS connection to the
-remote peer identified by _sa_, using the dialer _d_.
+The `nng_stream_dialer_dial()` attempts to establish a connection to the
+remote peer for the dialer _d_.
The operation is completed asynchronously, using _aio_.
-The address _sa_ must be in the `NNG_AF_INET` or `NNG_AF_INET6` families,
-and have a valid IPv4 or IPv6 address and TCP port number.
+TIP: The peer address is determined by the address specified using
+xref:nng_stream_dialer_alloc.3str.adoc[`nng_stream_dialer_alloc()`] or
+xref:nng_stream_dialer_alloc_url.3str.adoc[`nng_stream_dialer_alloc_url()`].
If a connection is successfully established, the _aio_ will have the
-resulting <<nng_tls.5#,`nng_tls`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
+resulting
+xref:nng_stream.5.adoc[`nng_stream`] object stored as its first output.
+(See
+xref:nng_aio_get_output.3.adoc[`nng_aio_get_output()`].)
== RETURN VALUES
@@ -49,17 +51,15 @@ None.
`NNG_ECLOSED`:: The dialer is closed.
`NNG_ECONNREFUSED`:: The connection was refused by the server.
`NNG_ECONNRESET`:: The connection was reset by the server.
-`NNG_ECRYPTO`:: Cryptographic or certificate validation error.
`NNG_ENOMEM`:: Insufficient free memory exists.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_alloc.3tls#,nng_tls_dialer_alloc(3tls)>>,
-<<nng_tls_dialer_close.3tls#,nng_tls_dialer_close(3tls)>>,
-<<nng_tls_dialer_free.3tls#,nng_tls_dialer_free(3tls)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc(3str)],
+xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close(3str)],
+xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free(3str)],
+xref:nng_aio.5.adoc[nng_aio(5)],
+xref:nng_stream.5.adoc[nng_stream(5)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_tls_dialer_free.3tls.adoc b/docs/man/nng_stream_dialer_free.3str.adoc
index b5e7b2bf..6669ca1e 100644
--- a/docs/man/nng_tls_dialer_free.3tls.adoc
+++ b/docs/man/nng_stream_dialer_free.3str.adoc
@@ -1,9 +1,9 @@
-= nng_tls_dialer_free(3tls)
+= nng_stream_dialer_free(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
-//
+
// This document 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
@@ -12,24 +12,25 @@
== NAME
-nng_tls_dialer_free - free TLS dialer
+nng_stream_dialer_free - free byte stream dialer
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_dialer_free(nng_tls_dialer *d);
+void nng_stream_dialer_free(nng_stream_dialer *d);
----
== DESCRIPTION
-The `nng_tls_dialer_free()` function closes the supplied TLS dialer _d_,
+The `nng_stream_dialer_free()` function closes the supplied
+byte stream dialer _d_,
and frees the underlying resources associated with it.
-If any <<nng_tls_dialer_dial.3tls#,dial>> operations using _d_ are
+If any
+xref:nng_stream_dialer_dial.3str.adoc[dial] operations using _d_ are
in progress, they will be terminated with an `NNG_ECLOSED` error condition.
WARNING: It is important that the application ensure that no further accesses
@@ -46,8 +47,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_alloc.3tls#,nng_tls_dialer_alloc(3tls)>>,
-<<nng_tls_dialer_close.3tls#,nng_tls_dialer_close(3tls)>>,
-<<nng_tls_dialer_dial.3tls#,nng_tls_dialer_dial(3tls)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc(3str)],
+xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close(3str)],
+xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial(3str)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_stream_dialer_get.3str.adoc b/docs/man/nng_stream_dialer_get.3str.adoc
new file mode 100644
index 00000000..b7043c74
--- /dev/null
+++ b/docs/man/nng_stream_dialer_get.3str.adoc
@@ -0,0 +1,143 @@
+= nng_stream_dialer_get(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_dialer_get - get option from byte stream dialer
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_dialer_get(nng_stream_dialer *d, const char *opt, void *val, size_t *sizep);
+
+int nng_stream_dialer_get_bool(nng_stream_dialer *d, const char *opt, bool *valp);
+
+int nng_stream_dialer_get_int(nng_stream_dialer *d, const char *opt, int *valp);
+
+int nng_stream_dialer_get_ms(nng_stream_dialer *d, const char *opt, nng_duration *valp);
+
+int nng_stream_dialer_get_ptr(nng_stream_dialer *d, const char *opt, void **valp);
+
+int nng_stream_dialer_get_size(nng_stream_dialer *d, const char *opt, size_t *valp);
+
+int nng_stream_dialer_get_addr(nng_stream_dialer *d, const char *opt, nng_sockaddr *valp);
+
+int nng_stream_dialer_get_string(nng_stream_dialer *d, const char *opt, char **valp);
+
+int nng_stream_dialer_get_uint64(nng_stream_dialer *d, const char *opt, uint64_t *valp);
+----
+
+== DESCRIPTION
+
+
+The `nng_stream_dialer_get()` functions are used to retrieve option values for the
+xref:nng_stream_dialer.5.adoc[byte stream dialer] _d_.
+
+The actual options that may be retrieved in this way vary.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)] and additional linked documents.
+
+=== Forms
+
+In all of these forms, the option _opt_ is retrieved from the connected
+byte stream dialer _d_.
+The forms vary based on the type of the option they take.
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_dialer_get()`::
+This function is untyped and can be used to retrieve the value of any option.
+The caller must store a pointer to a buffer to receive the value in _val_,
+and the size of the buffer shall be stored at the location referenced by
+_sizep_.
++
+When the function returns, the actual size of the data copied (or that
+would have been copied if sufficient space were present) is stored at
+the location referenced by _sizep_.
+If the caller's buffer is not large enough to hold the entire object,
+then the copy is truncated.
+Therefore the caller should check for truncation by verifying that the
+returned size in _sizep_ does not exceed the original buffer size.
++
+It is acceptable to pass `NULL` for _val_ if the value in _sizep_ is zero.
+This can be used to determine the size of the buffer needed to receive
+the object.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_dialer_get_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_dialer_get_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_dialer_get_ms()`::
+This function is used to retrieve time
+xref:nng_duration.5.adoc[durations]
+(such as timeouts), stored as a number of milliseconds.
+(The special value ((`NNG_DUR_INFINITE`)) means an infinite amount of time, and
+the special value ((`NNG_DUR_DEFAULT`)) means a context-specific default.)
+
+`nng_stream_dialer_get_ptr()`::
+This function is used to retrieve a pointer to structured data.
+The data referenced is generally managed using other functions.
+Note that this form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
++
+NOTE: Care must be taken to ensure that the application respects any
+considerations about the lifetime of the underyling object.
+See the documentation for the option for more specific guidance.
+
+`nng_stream_dialer_get_size()`::
+This function is used to retrieve a size,
+typically for buffer sizes, message maximum sizes, and similar options.
+
+`nng_stream_dialer_get_addr()`::
+This function is used to retrieve a
+xref:nng_sockaddr.5.adoc[socket address].
+
+`nng_stream_dialer_get_string()`::
+This function is used to retrieve a `NULL`-terminated string.
+This string is created from the source using
+xref:nng_strdup.3.adoc[`nng_strdup()`]
+and consequently must be freed by the caller using
+xref:nng_strfree.3.adoc[`nng_strfree()`] when it is no longer needed.
+
+`nng_stream_dialer_get_uint64()`::
+This function is used to retrieve a 64-bit unsigned value.
+This is typically used for identifiers, network
+numbers, and similar options.
+
+== RETURN VALUES
+
+These functions return 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The dialer is closed.
+`NNG_EINVAL`:: There was insufficient space to receive the object.
+ The amount of data actually needed is returned in _sizep_.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EWRITEONLY`:: The option may not read.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_set.3str.adoc[nng_stream_dialer_set(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_stream_dialer_set.3str.adoc b/docs/man/nng_stream_dialer_set.3str.adoc
new file mode 100644
index 00000000..1a1b6862
--- /dev/null
+++ b/docs/man/nng_stream_dialer_set.3str.adoc
@@ -0,0 +1,133 @@
+= nng_stream_dialer_set(3str)
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_dialer_set - set option on byte stream dialer
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_dialer_set(nng_stream_dialer *d, const char *name, const void *data, size_t size);
+
+int nng_stream_dialer_set_bool(nng_stream_dialer *d, const char *opt, int val);
+
+int nng_stream_dialer_set_int(nng_stream_dialer *d, const char *opt, int val);
+
+int nng_stream_dialer_set_ms(nng_stream_dialer *d, const char *opt, nng_duration val);
+
+int nng_stream_dialer_set_ptr(nng_stream_dialer *d, const char *opt, void *val);
+
+int nng_stream_dialer_set_size(nng_stream_dialer *d, const char *opt, size_t val);
+
+int nng_stream_dialer_set_string(nng_stream_dialer *d, const char *opt, const char *val);
+
+int nng_stream_dialer_set_uint64(nng_stream_dialer *d, const char *opt, uint64_t val);
+
+int nng_stream_dialer_set_addr(nng_stream_dialer *d, const char *opt, const nng_sockaddr *val);
+
+----
+
+== DESCRIPTION
+
+The `nng_stream_dialer_set()` functions are used to configure options for the
+xref:nng_stream.5.adoc[byte stream dialer] _d_.
+The actual options that may be configured in this way vary, and are
+specified by _opt_.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)].
+
+Additionally some transport-specific and protocol-specific options are
+documented with the transports and protocols themselves.
+
+=== Forms
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_dialer_set()`::
+This function is untyped, and can be used to configure any arbitrary data.
+The _val_ pointer addresses the data to copy, and _size_ is the
+size of the objected located at _val_.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_dialer_set_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_dialer_set_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_dialer_set_ms()`::
+This function is used to configure time durations (such as timeouts) using
+the type
+xref:nng_duration.5.adoc[`nng_duration`].
+The duration is an integer number of milliseconds.
+
+`nng_stream_dialer_set_ptr()`::
+This function is used to pass a pointer to structured data.
+The data referenced by is generally managed by other functions.
+For example, TLS configuration objects created with
+xref:nng_tls_config.3tls.adoc[`nng_tls_config_alloc()`]
+can be passed this way.
++
+NOTE: This form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
+Please see the documentation for the specific option for further details.
+
+`nng_stream_dialer_set_size()`::
+This function is used to configure a size, typically for buffer sizes,
+message maximum sizes, and similar options.
+
+`nng_stream_dialer_set_string()`::
+This function is used to pass configure a string.
+Strings passed this way must be legal UTF-8 or ASCII strings, terminated
+with a `NUL` (`\0`) byte.
+(Other constraints may apply as well, see the documentation for each option
+for details.)
+
+`nng_stream_dialer_set_uint64()`::
+This function is used to configure a 64-bit unsigned value/
+This is typically used for identifiers, network numbers,
+and similar options.
+
+`nng_stream_dialer_set_addr()`::
+This function is used to configure a
+xref:nng_sockaddr.5.adoc[socket address].
+The value is copied, and thus the caller may discard the supplied
+value immediately after this function returns.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The dialer is closed.
+`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EREADONLY`:: The option may not be modified.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_dialer_get.3str.adoc[nng_stream_dialer_get(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_ipc_options.5.adoc[nng_ipc_options(5)],
+xref:nng_tcp_options.5.adoc[nng_tcp_options(5)],
+xref:nng_tls_options.5.adoc[nng_tls_options(5)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)] \ No newline at end of file
diff --git a/docs/man/nng_tls_free.3tls.adoc b/docs/man/nng_stream_free.3str.adoc
index 62c2a81d..30679458 100644
--- a/docs/man/nng_tls_free.3tls.adoc
+++ b/docs/man/nng_stream_free.3str.adoc
@@ -1,4 +1,4 @@
-= nng_tls_free(3tls)
+= nng_stream_free(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
@@ -12,29 +12,31 @@
== NAME
-nng_tls_free - free TLS connection
+nng_stream_free - free byte stream
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_free(nng_tls *conn);
+void nng_stream_free(nng_stream *s);
----
== DESCRIPTION
-The `nng_tls_free()` function closes the supplied TLS connection, _conn_,
+The `nng_stream_free()` function closes the
+xref:nng_stream.5.adoc[byte stream] _s_,
and frees the underlying resources associated with it.
-If any operations are pending (such as <<nng_tls_send.3tls#,`nng_tls_send()`>>
-or <<nng_tls_recv.3tls#,`nng_tls_recv()`>> they will be terminated with
-an `NNG_ECLOSED` error condition.
+If any operations are pending, such as
+xref:nng_stream_send.3str.adoc[`nng_stream_send()`]
+or
+xref:nng_stream_recv.3str.adoc[`nng_stream_recv()`],
+they will be terminated with an `NNG_ECLOSED` error condition.
WARNING: It is important that the application ensure that no further accesses
-are made to _conn_, as the memory backing it will be reclaimed for other uses.
+are made to _s_, as the memory backing it will be reclaimed for other uses.
NOTE: Closing the connection while data is in transmission will likely
lead to loss of that data.
@@ -52,8 +54,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_close.3tls#,nng_tls_close(3tls)>>,
-<<nng_tls_recv.3tls#,nng_tls_recv(3tls)>>,
-<<nng_tls_send.3tls#,nng_tls_send(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_close.3str.adoc[nng_stream_close(3str)],
+xref:nng_stream_recv.3str.adoc[nng_stream_recv(3str)],
+xref:nng_stream_send.3str.adoc[nng_stream_send(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)]
diff --git a/docs/man/nng_stream_get.3str.adoc b/docs/man/nng_stream_get.3str.adoc
new file mode 100644
index 00000000..9a2b0220
--- /dev/null
+++ b/docs/man/nng_stream_get.3str.adoc
@@ -0,0 +1,146 @@
+= nng_stream_get(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_get - get option from byte stream
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_get(nng_stream *s, const char *opt, void *val, size_t *sizep);
+
+int nng_stream_get_bool(nng_stream *s, const char *opt, bool *valp);
+
+int nng_stream_get_int(nng_stream *s, const char *opt, int *valp);
+
+int nng_stream_get_ms(nng_stream *s, const char *opt, nng_duration *valp);
+
+int nng_stream_get_ptr(nng_stream *s, const char *opt, void **valp);
+
+int nng_stream_get_size(nng_stream *s, const char *opt, size_t *valp);
+
+int nng_stream_get_addr(nng_stream *s, const char *opt, nng_sockaddr *valp);
+
+int nng_stream_get_string(nng_stream *s, const char *opt, char **valp);
+
+int nng_stream_get_uint64(nng_stream *s, const char *opt, uint64_t *valp);
+
+----
+
+== DESCRIPTION
+
+The `nng_stream_get()` functions are used to retrieve option values for the
+xref:nng_stream.5.adoc[byte stream] _conn_.
+
+The actual options that may be retrieved in this way vary.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)] and additional linked documents.
+
+=== Forms
+
+In all of these forms, the option _opt_ is retrieved from the connected
+byte stream _s_.
+The forms vary based on the type of the option they take.
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_get()`::
+This function is untyped and can be used to retrieve the value of any option.
+The caller must store a pointer to a buffer to receive the value in _val_,
+and the size of the buffer shall be stored at the location referenced by
+_sizep_.
++
+When the function returns, the actual size of the data copied (or that
+would have been copied if sufficient space were present) is stored at
+the location referenced by _sizep_.
+If the caller's buffer is not large enough to hold the entire object,
+then the copy is truncated.
+Therefore the caller should check for truncation by verifying that the
+returned size in _sizep_ does not exceed the original buffer size.
++
+It is acceptable to pass `NULL` for _val_ if the value in _sizep_ is zero.
+This can be used to determine the size of the buffer needed to receive
+the object.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_get_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_get_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_get_ms()`::
+This function is used to retrieve time
+xref:nng_duration.5.adoc[durations]
+(such as timeouts), stored as a number of milliseconds.
+(The special value ((`NNG_DUR_INFINITE`)) means an infinite amount of time, and
+the special value ((`NNG_DUR_DEFAULT`)) means a context-specific default.)
+
+`nng_stream_get_ptr()`::
+This function is used to retrieve a pointer to structured data.
+The data referenced is generally managed using other functions.
+Note that this form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
++
+NOTE: Care must be taken to ensure that the application respects any
+considerations about the lifetime of the underyling object.
+See the documentation for the option for more specific guidance.
+
+`nng_stream_get_size()`::
+This function is used to retrieve a size,
+typically for buffer sizes, message maximum sizes, and similar options.
+
+`nng_stream_get_addr()`::
+This function is used to retrieve a
+xref:nng_sockaddr.5.adoc[socket address].
+
+`nng_stream_get_string()`::
+This function is used to retrieve a `NULL`-terminated string.
+This string is created from the source using
+xref:nng_strdup.3.adoc[`nng_strdup()`]
+and consequently must be freed by the caller using
+xref:nng_strfree.3.adoc[`nng_strfree()`] when it is no longer needed.
+
+`nng_stream_get_uint64()`::
+This function is used to retrieve a 64-bit unsigned value.
+This is typically used for identifiers, network
+numbers, and similar options.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection is closed.
+`NNG_EINVAL`:: There was insufficient space to receive the object.
+ The amount of data actually needed is returned in _sizep_.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EWRITEONLY`:: The option may not read.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_set.3str.adoc[nng_stream_set(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_ipc_options.5.adoc[nng_ipc_options(5)],
+xref:nng_tcp_options.5.adoc[nng_tcp_options(5)],
+xref:nng_tls_options.5.adoc[nng_tls_options(5)],
+xref:nng_stream.5.adoc[nng_stream(5)]
diff --git a/docs/man/nng_stream_listener.5.adoc b/docs/man/nng_stream_listener.5.adoc
new file mode 100644
index 00000000..c8966326
--- /dev/null
+++ b/docs/man/nng_stream_listener.5.adoc
@@ -0,0 +1,48 @@
+= nng_stream_listener(5)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener - byte stream listener
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+typedef struct nng_stream_dialer nng_stream_dialer;
+----
+
+== DESCRIPTION
+
+(((IPC, listener)))
+An `nng_stream_listener` is a handle to a byte stream "`listener`",
+which is responsible for accepting incoming connections and creating
+corresponding
+xref:nng_stream.5.adoc[`nng_stream`] from them.
+
+NOTE: The `nng_stream_listener` object is a low-level object for
+raw byte stream connections,
+and should not be confused with a high-level
+xref:nng_listener.5.adoc[`nng_listener`] object.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)],
+xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc(3str)],
+xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close(3str)],
+xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free(3str)],
+xref:nng_stream_listener_listen.3str.adoc[nng_stream_listener_listen(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)],
+xref:nng_stream_dialer.5.adoc[nng_stream_dialer(5)]
diff --git a/docs/man/nng_stream_listener_accept.3str.adoc b/docs/man/nng_stream_listener_accept.3str.adoc
new file mode 100644
index 00000000..f5ffbca5
--- /dev/null
+++ b/docs/man/nng_stream_listener_accept.3str.adoc
@@ -0,0 +1,64 @@
+= nng_stream_listener_accept(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener_accept - accept incoming byte stream connection
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+void nng_stream_listener_accept(nng_stream_listener *l, nng_aio *aio);
+----
+
+== DESCRIPTION
+
+The `nng_stream_listener_accept()` attempts to accept an incoming byte stream
+connection from a remote peer, using the listener _l_.
+The operation is completed asynchronously, using _aio_.
+
+This operation can only be done after the listener is already
+xref:nng_stream_listener_listen.3str.adoc[listening].
+
+If a connection is successfully established, the _aio_ will have the
+resulting
+xref:nng_stream.5.adoc[`nng_stream`] object stored as its first output,
+which can be retrieved with
+xref:nng_aio_get_output.3.adoc[`nng_aio_get_output()`].
+
+== RETURN VALUES
+
+None.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECANCELED`:: The operation was aborted.
+`NNG_ECLOSED`:: The listener is closed.
+`NNG_ECONNRESET`:: The connection was reset by the peer.
+`NNG_ENOMEM`:: Insufficient free memory exists.
+`NNG_ESTATE`:: The listener is not not listening.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc(3str)],
+xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close(3str)],
+xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free(3str)],
+xref:nng_stream_listener_listen.3str.adoc[nng_stream_listener_listen(3str)],
+xref:nng_aio.5.adoc[nng_aio(5)],
+xref:nng_stream.5.adoc[nng_stream(5)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_stream_listener_alloc.3str.adoc b/docs/man/nng_stream_listener_alloc.3str.adoc
new file mode 100644
index 00000000..966866ba
--- /dev/null
+++ b/docs/man/nng_stream_listener_alloc.3str.adoc
@@ -0,0 +1,70 @@
+= nng_stream_listener_alloc(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener_alloc - allocate byte stream listener
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_listener_alloc(nng_stream_listener **lp, const char *addr);
+
+int nng_stream_listener_alloc_url(nng_stream_listener **lp, const nng_url *url);
+----
+
+== DESCRIPTION
+
+These functions allocates a listener for byte streams.
+Listeners create
+xref:nng_stream.5.adoc[`nng_stream`] objects by accepting incoming
+connections, via the
+xref:nng_stream_listener_accept.3str.adoc[`nng_stream_listener_accept()`]
+function.
+
+The first form, `nng_stream_listener_alloc()`, connects to the address
+specified by _addr_, which should be a string representing a URL.
+
+The second form, `nng_stream_listener_alloc_url()`, takes a pre-parsed
+or pre-constructed
+xref:nng_url.5.adoc[`nng_url`] object to determine the remote address.
+
+These functions may support different URL schemes, such as
+`ipc://`, `tcp://`, `tls+tcp://`, or `ws://`.
+
+Both forms store the listener in the location referenced by _lp_.
+
+== RETURN VALUES
+
+These functions return 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ENOMEM`:: Insufficient free memory exists.
+`NNG_ENOTSUP`:: The URL scheme is not supported by the implementation.
+`NNG_EADDRINVAL`:: The URL requested is invalid.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)]
+xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close(3str)]
+xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free(3str)]
+xref:nng_stream_listener_get.3str.adoc[nng_stream_listener_get(3str)]
+xref:nng_stream_listener_listen.3str.adoc[nng_stream_listener_listen(3str)]
+xref:nng_stream_listener_set.3str.adoc[nng_stream_listener_set(3str)]
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_tls_listener_close.3tls.adoc b/docs/man/nng_stream_listener_close.3str.adoc
index 26120cee..a810509e 100644
--- a/docs/man/nng_tls_listener_close.3tls.adoc
+++ b/docs/man/nng_stream_listener_close.3str.adoc
@@ -1,4 +1,4 @@
-= nng_tls_listener_close(3tls)
+= nng_stream_listener_close(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
@@ -12,32 +12,34 @@
== NAME
-nng_tls_listener_close - close TLS listener
+nng_stream_listener_close - close byte stream listener
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-void nng_tls_listener_close(nng_tls_listener *l);
+void nng_stream_listener_close(nng_stream_listener *l);
----
== DESCRIPTION
-The `nng_tls_listener_close()` function closes the supplied TLS listener _l_,
+The `nng_stream_listener_close()` function closes the supplied connected byte
+stream listener _l_,
but does not free the underlying resources associated with it.
-If any <<nng_tls_listener_accept.3tls#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
+If any
+xref:nng_stream_listener_accept.3str.adoc[accept]
+operations using _d_ are
+in progress, they will be terminated with an `NNG_ECLOSED` error condition.
Furthermore any future accesses to the listener _l_ will also result in
`NNG_ECLOSED`.
NOTE: This function does not release the memory for the listener, so the
application should still free the memory using
-<<nng_tls_listener_free.3tls#,`nng_tls_listener_free()`>>
+xref:nng_stream_listener_free.3str.adoc[`nng_stream_listener_free()`]
once it is certain that nothing else is using it.
== RETURN VALUES
@@ -51,8 +53,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc(3tls)>>,
-<<nng_tls_listener_accept.3tls#,nng_tls_listener_accept(3tls)>>,
-<<nng_tls_listener_free.3tls#,nng_tls_listener_free(3tls)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)],
+xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc(3str)],
+xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free(3str)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_ipc_dialer_free.3ipc.adoc b/docs/man/nng_stream_listener_free.3str.adoc
index ff2bf025..aecd8895 100644
--- a/docs/man/nng_ipc_dialer_free.3ipc.adoc
+++ b/docs/man/nng_stream_listener_free.3str.adoc
@@ -1,9 +1,9 @@
-= nng_ipc_dialer_free(3ipc)
+= nng_stream_listener_free(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
-//
+
// This document 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
@@ -12,29 +12,29 @@
== NAME
-nng_ipc_dialer_free - free IPC dialer
+nng_stream_listener_free - free byte stream listener
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-void nng_ipc_dialer_free(nng_ipc_dialer *d);
+void nng_stream_listener_free(nng_stream_listener *)l;
----
== DESCRIPTION
-The `nng_ipc_dialer_free()` function closes the supplied IPC dialer _d_,
+The `nng_stream_listener_free()` function closes the supplied
+byte stream listener _l_,
and frees the underlying resources associated with it.
-If any <<nng_ipc_dialer_dial.3ipc#,dial>> operations
- using _d_ are
+If any
+xref:nng_stream_listener_accept.3str.adoc[accept] operations using __l are
in progress, they will be terminated with an `NNG_ECLOSED` error condition.
WARNING: It is important that the application ensure that no further accesses
-are made to _d_, as the memory backing it will be reclaimed for other uses.
+are made to _l_, as the memory backing it will be reclaimed for other uses.
== RETURN VALUES
@@ -47,8 +47,8 @@ None.
== SEE ALSO
[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_ipc_dialer_alloc.3ipc#,nng_ipc_dialer_alloc(3ipc)>>,
-<<nng_ipc_dialer_close.3ipc#,nng_ipc_dialer_close(3ipc)>>,
-<<nng_ipc_dialer_dial.3ipc#,nng_ipc_dialer_dial(3ipc)>>,
-<<nng_ipc_dialer.5#,nng_ipc_dialer(5)>>
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)],
+xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc(3str)],
+xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close(3str)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_stream_listener_get.3str.adoc b/docs/man/nng_stream_listener_get.3str.adoc
new file mode 100644
index 00000000..87c25158
--- /dev/null
+++ b/docs/man/nng_stream_listener_get.3str.adoc
@@ -0,0 +1,144 @@
+= nng_stream_listener_get(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener_get - get option from byte stream listener
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_listener_get(nng_stream_listener *l, const char *opt, void *val, size_t *sizep);
+
+int nng_stream_listener_get_bool(nng_stream_listener *l, const char *opt, bool *valp);
+
+int nng_stream_listener_get_int(nng_stream_listener *l, const char *opt, int *valp);
+
+int nng_stream_listener_get_ms(nng_stream_listener *l, const char *opt, nng_duration *valp);
+
+int nng_stream_listener_get_ptr(nng_stream_listener *l, const char *opt, void **valp);
+
+int nng_stream_listener_get_size(nng_stream_listener *l, const char *opt, size_t *valp);
+
+int nng_stream_listener_get_addr(nng_stream_listener *l, const char *opt, nng_sockaddr *valp);
+
+int nng_stream_listener_get_string(nng_stream_listener *l, const char *opt, char **valp);
+
+int nng_stream_listener_get_uint64(nng_stream_listener *l, const char *opt, uint64_t *valp);
+----
+
+== DESCRIPTION
+
+
+The `nng_stream_listener_get()` functions are used to retrieve option values
+for the
+xref:nng_stream_listener.5.adoc[byte stream listener] _l_.
+
+The actual options that may be retrieved in this way vary.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)] and additional linked documents.
+
+=== Forms
+
+In all of these forms, the option _opt_ is retrieved from the connected
+byte stream listener _l_.
+The forms vary based on the type of the option they take.
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_listener_get()`::
+This function is untyped and can be used to retrieve the value of any option.
+The caller must store a pointer to a buffer to receive the value in _val_,
+and the size of the buffer shall be stored at the location referenced by
+_sizep_.
++
+When the function returns, the actual size of the data copied (or that
+would have been copied if sufficient space were present) is stored at
+the location referenced by _sizep_.
+If the caller's buffer is not large enough to hold the entire object,
+then the copy is truncated.
+Therefore the caller should check for truncation by verifying that the
+returned size in _sizep_ does not exceed the original buffer size.
++
+It is acceptable to pass `NULL` for _val_ if the value in _sizep_ is zero.
+This can be used to determine the size of the buffer needed to receive
+the object.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_listener_get_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_listener_get_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_listener_get_ms()`::
+This function is used to retrieve time
+xref:nng_duration.5.adoc[durations]
+(such as timeouts), stored as a number of milliseconds.
+(The special value ((`NNG_DUR_INFINITE`)) means an infinite amount of time, and
+the special value ((`NNG_DUR_DEFAULT`)) means a context-specific default.)
+
+`nng_stream_listener_get_ptr()`::
+This function is used to retrieve a pointer to structured data.
+The data referenced is generally managed using other functions.
+Note that this form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
++
+NOTE: Care must be taken to ensure that the application respects any
+considerations about the lifetime of the underyling object.
+See the documentation for the option for more specific guidance.
+
+`nng_stream_listener_get_size()`::
+This function is used to retrieve a size,
+typically for buffer sizes, message maximum sizes, and similar options.
+
+`nng_stream_listener_get_addr()`::
+This function is used to retrieve a
+xref:nng_sockaddr.5.adoc[socket address].
+
+`nng_stream_listener_get_string()`::
+This function is used to retrieve a `NULL`-terminated string.
+This string is created from the source using
+xref:nng_strdup.3.adoc[`nng_strdup()`]
+and consequently must be freed by the caller using
+xref:nng_strfree.3.adoc[`nng_strfree()`] when it is no longer needed.
+
+`nng_stream_listener_get_uint64()`::
+This function is used to retrieve a 64-bit unsigned value.
+This is typically used for identifiers, network
+numbers, and similar options.
+
+== RETURN VALUES
+
+These functions return 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The listener is closed.
+`NNG_EINVAL`:: There was insufficient space to receive the object.
+ The amount of data actually needed is returned in _sizep_.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EWRITEONLY`:: The option may not read.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_set.3str.adoc[nng_stream_listener_set(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_stream_listener_listen.3str.adoc b/docs/man/nng_stream_listener_listen.3str.adoc
new file mode 100644
index 00000000..e8473b52
--- /dev/null
+++ b/docs/man/nng_stream_listener_listen.3str.adoc
@@ -0,0 +1,66 @@
+= nng_stream_listener_listen(3str)
+//
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener_listen - bind listener to configured address
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_listener_listen(nng_stream_listener *l);
+----
+
+== DESCRIPTION
+
+The `nng_stream_listener_listen()` attempts to bind the listener _l_
+to the local address specified when the listener was created.
+
+This must generally be done before accepting incoming connections using
+xref:nng_stream_listener_accept.3str.adoc[`nng_stream_listener_accept()`].
+
+For some transports this will also perform other actiosn. For example,
+with TCP listeners it will configure the
+underlying port into passive mode, ready to
+accept an incoming connection, and established a listen queue
+for receiving incoming connections.
+
+If binding the listener requires allocation of an address (for example
+when a TCP port number of zero is specified, indicating that an
+ephemeral port should be used), this operation will allocate that
+resource.
+This can permit retrieval of the selected address using
+xref:nng_stream_listener_get.3str.adoc[`nng_stream_listener_get()`],
+typically with the
+xref:nng_options.5.adoc#NNG_OPT_LOCADDR[`NNG_OPT_LOCADDR`] option.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_EADDRINUSE`:: The address is already in use.
+`NNG_EADDRINVAL`:: The address is invalid or unavailable.
+`NNG_ECLOSED`:: The listener has been closed.
+`NNG_ESTATE`:: The listener is already bound.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept(3str)],
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)]
diff --git a/docs/man/nng_stream_listener_set.3str.adoc b/docs/man/nng_stream_listener_set.3str.adoc
new file mode 100644
index 00000000..4fd47d4f
--- /dev/null
+++ b/docs/man/nng_stream_listener_set.3str.adoc
@@ -0,0 +1,133 @@
+= nng_stream_listener_set(3str)
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_listener_set - set option on byte stream listener
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_listener_set(nng_stream_listener *l, const char *name, const void *data, size_t size);
+
+int nng_stream_listener_set_bool(nng_stream_listener *l, const char *opt, int val);
+
+int nng_stream_listener_set_int(nng_stream_listener *l, const char *opt, int val);
+
+int nng_stream_listener_set_ms(nng_stream_listener *l, const char *opt, nng_duration val);
+
+int nng_stream_listener_set_ptr(nng_stream_listener *l, const char *opt, void *val);
+
+int nng_stream_listener_set_size(nng_stream_listener *l, const char *opt, size_t val);
+
+int nng_stream_listener_set_string(nng_stream_listener *l, const char *opt, const char *val);
+
+int nng_stream_listener_set_uint64(nng_stream_listener *l, const char *opt, uint64_t val);
+
+int nng_stream_listener_set_addr(nng_stream_listener *l, const char *opt, const nng_sockaddr *val);
+
+----
+
+== DESCRIPTION
+
+The `nng_stream_listener_set()` functions are used to configure options for the
+xref:nng_stream.5.adoc[byte stream listener] _l_.
+The actual options that may be configured in this way vary, and are
+specified by _opt_.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)].
+
+Additionally some transport-specific and protocol-specific options are
+documented with the transports and protocols themselves.
+
+=== Forms
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_listener_set()`::
+This function is untyped, and can be used to configure any arbitrary data.
+The _val_ pointer addresses the data to copy, and _size_ is the
+size of the objected located at _val_.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_listener_set_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_listener_set_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_listener_set_ms()`::
+This function is used to configure time durations (such as timeouts) using
+the type
+xref:nng_duration.5.adoc[`nng_duration`].
+The duration is an integer number of milliseconds.
+
+`nng_stream_listener_set_ptr()`::
+This function is used to pass a pointer to structured data.
+The data referenced by is generally managed by other functions.
+For example, TLS configuration objects created with
+xref:nng_tls_config.3tls.adoc[`nng_tls_config_alloc()`]
+can be passed this way.
++
+NOTE: This form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
+Please see the documentation for the specific option for further details.
+
+`nng_stream_listener_set_size()`::
+This function is used to configure a size, typically for buffer sizes,
+message maximum sizes, and similar options.
+
+`nng_stream_listener_set_string()`::
+This function is used to pass configure a string.
+Strings passed this way must be legal UTF-8 or ASCII strings, terminated
+with a `NUL` (`\0`) byte.
+(Other constraints may apply as well, see the documentation for each option
+for details.)
+
+`nng_stream_listener_set_uint64()`::
+This function is used to configure a 64-bit unsigned value/
+This is typically used for identifiers, network numbers,
+and similar options.
+
+`nng_stream_listener_set_addr()`::
+This function is used to configure a
+xref:nng_sockaddr.5.adoc[socket address].
+The value is copied, and thus the caller may discard the supplied
+value immediately after this function returns.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The listener is closed.
+`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EREADONLY`:: The option may not be modified.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_listener_get.3str.adoc[nng_stream_listener_get(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_ipc_options.5.adoc[nng_ipc_options(5)],
+xref:nng_tcp_options.5.adoc[nng_tcp_options(5)],
+xref:nng_tls_options.5.adoc[nng_tls_options(5)],
+xref:nng_stream_listener.5.adoc[nng_stream_listener(5)] \ No newline at end of file
diff --git a/docs/man/nng_tcp_recv.3tcp.adoc b/docs/man/nng_stream_recv.3str.adoc
index 787ebfd3..3acb1921 100644
--- a/docs/man/nng_tcp_recv.3tcp.adoc
+++ b/docs/man/nng_stream_recv.3str.adoc
@@ -1,7 +1,8 @@
-= nng_tcp_recv(3tcp)
+= nng_stream_send(3str)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -11,41 +12,39 @@
== NAME
-nng_tcp_recv - receive from TCP connection
+nng_stream_send - receive from byte stream
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-void nng_tcp_recv(nng_tcp *conn, nng_aio *aio);
+void nng_stream_send(nng_stream *s, nng_aio *aio);
----
== DESCRIPTION
-The `nng_tcp_recv()` function starts an asynchronous receive from the
-TCP connection _conn_, into the scatter/gather vector located in the
+The `nng_stream_send()` function starts an asynchronous receive from the
+xref:nng_stream.5.adoc[byte stream] _s_
+into the scatter/gather vector located in the
asynchronous I/O structure _aio_.
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
+NOTE: The
+xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`] function must have been
called first, to set the scatter/gather vector for _aio_.
This function returns immediately, with no return value.
Completion of the operation is signaled via the _aio_,
and the final result may be obtained via
-<<nng_aio_result.3#,`nng_aio_result()`>>.
+xref:nng_aio_result.3.adoc[`nng_aio_result()`].
That result will either be zero or an error code.
The I/O operation completes as soon as at least one byte has been
received, or an error has occurred.
Therefore, the number of bytes read may be less than requested.
The actual number of bytes read can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
-
-NOTE: While TCP has the notion of urgent (out-of-band) delivery, that is
-used by very few protocols and this API does not support it.
+xref:nng_aio_count.3.adoc[`nng_aio_count()`].
== RETURN VALUES
@@ -64,11 +63,11 @@ None.
== SEE ALSO
[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_close.3tcp#,nng_tcp_close(3tcp)>>,
-<<nng_tcp_send.3tcp#,nng_tcp_send(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>
+xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)],
+xref:nng_aio_count.3.adoc[nng_aio_count(3)],
+xref:nng_aio_result.3.adoc[nng_aio_result(3)],
+xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)],
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_close.3str.adoc[nng_stream_close(3str)],
+xref:nng_stream_send.3str.adoc[nng_stream_send(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)]
diff --git a/docs/man/nng_ipc_send.3ipc.adoc b/docs/man/nng_stream_send.3str.adoc
index d606ddd9..2ae7355a 100644
--- a/docs/man/nng_ipc_send.3ipc.adoc
+++ b/docs/man/nng_stream_send.3str.adoc
@@ -1,6 +1,6 @@
-= nng_ipc_send(3ipc)
+= nng_stream_send(3str)
//
-// 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,37 +12,40 @@
== NAME
-nng_ipc_send - send to IPC connection
+nng_stream_send - send to byte stream
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
-void nng_ipc_send(nng_ipc *conn, nng_aio *aio);
+void nng_stream_send(nng_stream *s, nng_aio *aio);
----
== DESCRIPTION
-The `nng_ipc_send()` function starts an asynchronous send over the
-IPC connection _conn_ from the scatter/gather vector located in the
+The `nng_stream_send()` function starts an asynchronous send over the
+xref:nng_stream.5.adoc[byte stream] _s_
+from the scatter/gather vector located in the
asynchronous I/O structure _aio_.
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
+NOTE: The
+xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`]
+function must have been
called first, to set the scatter/gather vector for _aio_.
This function returns immediately, with no return value.
Completion of the operation is signaled via the _aio_, and the final
-result may be obtained via <<nng_aio_result.3#,`nng_aio_result()`>>.
+result may be obtained via
+xref:nng_aio_result.3.adoc[`nng_aio_result()`].
That result will either be zero or an error code.
The I/O operation completes as soon as at least one byte has been
sent, or an error has occurred.
Therefore, the number of bytes sent may be less than requested.
The actual number of bytes sent can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
+xref:nng_aio_count.3.adoc[`nng_aio_count()`].
== RETURN VALUES
@@ -61,11 +64,11 @@ None.
== SEE ALSO
[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_ipc_close.3ipc#,nng_ipc_close(3ipc)>>,
-<<nng_ipc_recv.3ipc#,nng_ipc_recv(3ipc)>>,
-<<nng_ipc.5#,nng_ipc(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
+xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)],
+xref:nng_aio_count.3.adoc[nng_aio_count(3)],
+xref:nng_aio_result.3.adoc[nng_aio_result(3)],
+xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)],
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_close.3str.adoc#[nng_stream_close(3str)],
+xref:nng_stream_recv.3str.adoc#[nng_stream_recv(3str)],
+xref:nng_stream.5.adoc[nng_stream(5)]
diff --git a/docs/man/nng_stream_set.3str.adoc b/docs/man/nng_stream_set.3str.adoc
new file mode 100644
index 00000000..cc6d4610
--- /dev/null
+++ b/docs/man/nng_stream_set.3str.adoc
@@ -0,0 +1,133 @@
+= nng_stream_set(3str)
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+// Copyright 2019 Devolutions <info@devolutions.net>
+//
+// This document 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.
+//
+
+== NAME
+
+nng_stream_set - set option on byte stream
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+
+int nng_stream_set(nng_stream *s, const char *name, const void *data, size_t size);
+
+int nng_stream_set_bool(nng_stream *s, const char *opt, int val);
+
+int nng_stream_set_int(nng_stream *s, const char *opt, int val);
+
+int nng_stream_set_ms(nng_stream *s, const char *opt, nng_duration val);
+
+int nng_stream_set_ptr(nng_stream *s, const char *opt, void *val);
+
+int nng_stream_set_size(nng_stream *s, const char *opt, size_t val);
+
+int nng_stream_set_string(nng_stream *s, const char *opt, const char *val);
+
+int nng_stream_set_uint64(nng_stream *s, const char *opt, uint64_t val);
+
+int nng_stream_set_addr(nng_stream *s, const char *opt, const nng_sockaddr *val);
+
+----
+
+== DESCRIPTION
+
+The `nng_stream_set()` functions are used to configure options for the
+xref:nng_stream.5.adoc[byte stream] _s_.
+The actual options that may be configured in this way vary, and are
+specified by _opt_.
+A number of them are documented in
+xref:nng_options.5.adoc[nng_options(5)].
+
+Additionally some transport-specific and protocol-specific options are
+documented with the transports and protocols themselves.
+
+=== Forms
+
+The details of the type, size, and semantics of the option will depend
+on the actual option, and will be documented with the option itself.
+
+`nng_stream_set()`::
+This function is untyped, and can be used to configure any arbitrary data.
+The _val_ pointer addresses the data to copy, and _size_ is the
+size of the objected located at _val_.
++
+TIP: It may be easier to use one of the typed forms of this function.
+
+`nng_stream_set_bool()`::
+This function is for options which take a Boolean (`bool`).
+
+`nng_stream_set_int()`::
+This function is for options which take an integer (`int`).
+
+`nng_stream_set_ms()`::
+This function is used to configure time durations (such as timeouts) using
+the type
+xref:nng_duration.5.adoc[`nng_duration`].
+The duration is an integer number of milliseconds.
+
+`nng_stream_set_ptr()`::
+This function is used to pass a pointer to structured data.
+The data referenced by is generally managed by other functions.
+For example, TLS configuration objects created with
+xref:nng_tls_config.3tls.adoc[`nng_tls_config_alloc()`]
+can be passed this way.
++
+NOTE: This form is somewhat special in that the object is generally
+not copied, but instead the *pointer* to the object is copied.
+Please see the documentation for the specific option for further details.
+
+`nng_stream_set_size()`::
+This function is used to configure a size, typically for buffer sizes,
+message maximum sizes, and similar options.
+
+`nng_stream_set_string()`::
+This function is used to pass configure a string.
+Strings passed this way must be legal UTF-8 or ASCII strings, terminated
+with a `NUL` (`\0`) byte.
+(Other constraints may apply as well, see the documentation for each option
+for details.)
+
+`nng_stream_set_uint64()`::
+This function is used to configure a 64-bit unsigned value/
+This is typically used for identifiers, network numbers,
+and similar options.
+
+`nng_stream_set_addr()`::
+This function is used to configure a
+xref:nng_sockaddr.5.adoc[socket address].
+The value is copied, and thus the caller may discard the supplied
+value immediately after this function returns.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection is closed.
+`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
+`NNG_ENOTSUP`:: The option is not supported.
+`NNG_EREADONLY`:: The option may not be modified.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_strerror.3.adoc[nng_strerror(3)],
+xref:nng_stream_get.3str.adoc[nng_stream_get(3str)],
+xref:nng_options.5.adoc[nng_options(5)],
+xref:nng_ipc_options.5.adoc[nng_ipc_options(5)],
+xref:nng_tcp_options.5.adoc[nng_tcp_options(5)],
+xref:nng_tls_options.5.adoc[nng_tls_options(5)],
+xref:nng_stream.5.adoc[nng_stream(5)] \ No newline at end of file
diff --git a/docs/man/nng_tcp_close.3tcp.adoc b/docs/man/nng_tcp_close.3tcp.adoc
deleted file mode 100644
index 5e68398b..00000000
--- a/docs/man/nng_tcp_close.3tcp.adoc
+++ /dev/null
@@ -1,60 +0,0 @@
-= nng_tcp_close(3tcp)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_close - close TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_close(nng_tcp *conn);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_close()` function closes the supplied TCP connection, _conn_.
-
-If any operations are pending (such as <<nng_tcp_send.3tcp#,`nng_tcp_send()`>>
-or <<nng_tcp_recv.3tcp#,`nng_tcp_recv()`>> they will be terminated with
-an `NNG_ECLOSED` error condition.
-Also, any new operations will fail with `NNG_ECLOSED` after the connection
-is closed.
-
-NOTE: Closing the connection while data is in transmission will likely
-lead to loss of that data.
-There is no automatic linger or flush to ensure that the socket send buffers
-have completely transmitted.
-
-NOTE: Closing the connection does not free the resources associated with it.
-Once it is certain that no more operations are pending on the connection,
-it should be freed with <<nng_tcp_free.3tcp#,`nng_tcp_free()`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_free.3tcp#,nng_tcp_free(3tcp)>>,
-<<nng_tcp_recv.3tcp#,nng_tcp_recv(3tcp)>>,
-<<nng_tcp_send.3tcp#,nng_tcp_send(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_dialer.5.adoc b/docs/man/nng_tcp_dialer.5.adoc
deleted file mode 100644
index 651afd02..00000000
--- a/docs/man/nng_tcp_dialer.5.adoc
+++ /dev/null
@@ -1,49 +0,0 @@
-= nng_tcp_dialer(5)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer - TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-typedef struct nng_tcp_dialer_s nng_tcp_dialer;
-----
-
-== DESCRIPTION
-
-(((TCP, dialer)))
-An `nng_tcp_dialer` is a handle to a TCP "`dialer`", which is responsible for
-creating connections (<<nng_tcp.5#,`nng_tcp`>> objects) by connecting to
-remote systems.
-
-NOTE: The `nng_tcp_dialer` object is used for raw TCP connections, and
-should not be confused with a dialer object created using the
-<<nng_tcp.7#,nng_tcp(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_tcp.7#,`nng_tcp`>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_tcp_dialer_alloc.3tcp#,nng_tcp_dialer_alloc(3tcp)>>,
-<<nng_tcp_dialer_close.3tcp#,nng_tcp_dialer_close(3tcp)>>,
-<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial(3tcp)>>,
-<<nng_tcp_dialer_free.3tcp#,nng_tcp_dialer_free(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>,
-<<nng_tcp.7#,nng_tcp(7)>>
diff --git a/docs/man/nng_tcp_dialer_alloc.3tcp.adoc b/docs/man/nng_tcp_dialer_alloc.3tcp.adoc
deleted file mode 100644
index 3e215695..00000000
--- a/docs/man/nng_tcp_dialer_alloc.3tcp.adoc
+++ /dev/null
@@ -1,50 +0,0 @@
-= nng_tcp_dialer_alloc(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_alloc - allocate TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_dialer_alloc(nng_tcp_dialer *dp);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_alloc()` allocates a TCP dialer, which can be used
-to create outgoing connections over TCP, and stores a pointer to it
-it in the location referenced by _dp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_close.3tcp#,nng_tcp_dialer_close(3tcp)>>,
-<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial(3tcp)>>,
-<<nng_tcp_dialer_free.3tcp#,nng_tcp_dialer_free(3tcp)>>,
-<<nng_tcp_dialer_getopt.3tcp#,nng_tcp_dialer_getopt(3tcp)>>,
-<<nng_tcp_dialer_setopt.3tcp#,nng_tcp_dialer_setopt(3tcp)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_dialer_close.3tcp.adoc b/docs/man/nng_tcp_dialer_close.3tcp.adoc
deleted file mode 100644
index b325a3a0..00000000
--- a/docs/man/nng_tcp_dialer_close.3tcp.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-= nng_tcp_dialer_close(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_close - close TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_dialer_close(nng_tcp_dialer *d);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_close()` function closes the supplied TCP dialer _d_,
-but does not free the underlying resources associated with it.
-
-If any <<nng_tcp_dialer_dial.3tcp#,dial>> operations using _d_ are
-in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-Furthermore any future accesses to the dialer _d_ will also result in
-`NNG_ECLOSED`.
-
-NOTE: This function does not release the memory for the dialer, so the
-application should still free the memory using
-<<nng_tcp_dialer_free.3tcp#,`nng_tcp_dialer_free()`>>
-once it is certain that nothing else is using it.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_alloc.3tcp#,nng_tcp_dialer_alloc(3tcp)>>,
-<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial(3tcp)>>,
-<<nng_tcp_dialer_free.3tcp#,nng_tcp_dialer_free(3tcp)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_dialer_dial.3tcp.adoc b/docs/man/nng_tcp_dialer_dial.3tcp.adoc
deleted file mode 100644
index 3f0c8ba6..00000000
--- a/docs/man/nng_tcp_dialer_dial.3tcp.adoc
+++ /dev/null
@@ -1,63 +0,0 @@
-= nng_tcp_dialer_dial(3tcp)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_dial - initiate outgoing TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_dialer_dial(nng_tcp_dialer *d, const nng_sockaddr *sa, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_dial()` attempts to establish a TCP connection to the
-remote peer identified by _sa_, using the dialer _d_.
-The operation is completed asynchronously, using _aio_.
-
-The address _sa_ must be in the `NNG_AF_INET` or `NNG_AF_INET6` families,
-and have a valid IPv4 or IPv6 address and TCP port number.
-
-If a connection is successfully established, the _aio_ will have the
-resulting <<nng_tcp.5#,`nng_tcp`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_EADDRINVAL`:: The address specified is invalid.
-`NNG_ECANCELED`:: The operation was aborted.
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_ECONNREFUSED`:: The connection was refused by the server.
-`NNG_ECONNRESET`:: The connection was reset by the server.
-`NNG_ENOMEM`:: Insufficient free memory exists.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_alloc.3tcp#,nng_tcp_dialer_alloc(3tcp)>>,
-<<nng_tcp_dialer_close.3tcp#,nng_tcp_dialer_close(3tcp)>>,
-<<nng_tcp_dialer_free.3tcp#,nng_tcp_dialer_free(3tcp)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_dialer_free.3tcp.adoc b/docs/man/nng_tcp_dialer_free.3tcp.adoc
deleted file mode 100644
index 7b15fc39..00000000
--- a/docs/man/nng_tcp_dialer_free.3tcp.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_tcp_dialer_free(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_free - free TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_dialer_free(nng_tcp_dialer *d);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_free()` function closes the supplied TCP dialer _d_,
-and frees the underlying resources associated with it.
-
-If any <<nng_tcp_dialer_dial.3tcp#,dial>> operations using _d_ are
-in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _d_, as the memory backing it will be reclaimed for other uses.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_alloc.3tcp#,nng_tcp_dialer_alloc(3tcp)>>,
-<<nng_tcp_dialer_close.3tcp#,nng_tcp_dialer_close(3tcp)>>,
-<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial(3tcp)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_dialer_getopt.3tcp.adoc b/docs/man/nng_tcp_dialer_getopt.3tcp.adoc
deleted file mode 100644
index b99b17eb..00000000
--- a/docs/man/nng_tcp_dialer_getopt.3tcp.adoc
+++ /dev/null
@@ -1,69 +0,0 @@
-= nng_tcp_dialer_getopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_getopt - get option from TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_getopt(nng_tcp_dialer *d, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_getopt()` is used to retrieve the value of the option _name_
-for the <<nng_tcp_dialer.5#,TCP dialer>> _d_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TCP dialers are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_setopt.3tcp#,nng_tcp_dialer_setopt(3tcp)>>,
-<<nng_tcp_getopt.3tcp#,nng_tcp_getopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_dialer_setopt.3tcp.adoc b/docs/man/nng_tcp_dialer_setopt.3tcp.adoc
deleted file mode 100644
index ae06cc3c..00000000
--- a/docs/man/nng_tcp_dialer_setopt.3tcp.adoc
+++ /dev/null
@@ -1,63 +0,0 @@
-= nng_tcp_dialer_setopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_dialer_setopt - set option on TCP dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_dialer_setopt(nng_tcp_dialer *d, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_dialer_setopt()` is used to set the option _name_ for the
-<<nng_tcp_dialer.5#,TCP dialer>> _d_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TCP dialers are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_dialer_getopt.3tcp#,nng_tcp_dialer_getopt(3tcp)>>,
-<<nng_tcp_setopt.3tcp#,nng_tcp_setopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>
diff --git a/docs/man/nng_tcp_free.3tcp.adoc b/docs/man/nng_tcp_free.3tcp.adoc
deleted file mode 100644
index c87380cd..00000000
--- a/docs/man/nng_tcp_free.3tcp.adoc
+++ /dev/null
@@ -1,58 +0,0 @@
-= nng_tcp_free(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_free - free TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_free(nng_tcp *conn);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_free()` function closes the supplied TCP connection, _conn_,
-and frees the underlying resources associated with it.
-
-If any operations are pending (such as <<nng_tcp_send.3tcp#,`nng_tcp_send()`>>
-or <<nng_tcp_recv.3tcp#,`nng_tcp_recv()`>> they will be terminated with
-an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _conn_, as the memory backing it will be reclaimed for other uses.
-
-NOTE: Closing the connection while data is in transmission will likely
-lead to loss of that data.
-There is no automatic linger or flush to ensure that the socket send buffers
-have completely transmitted.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_close.3tcp#,nng_tcp_close(3tcp)>>,
-<<nng_tcp_recv.3tcp#,nng_tcp_recv(3tcp)>>,
-<<nng_tcp_send.3tcp#,nng_tcp_send(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_getopt.3tcp.adoc b/docs/man/nng_tcp_getopt.3tcp.adoc
deleted file mode 100644
index f785791b..00000000
--- a/docs/man/nng_tcp_getopt.3tcp.adoc
+++ /dev/null
@@ -1,68 +0,0 @@
-= nng_tcp_getopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_getopt - get option from TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_getopt(nng_tcp *conn, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_getopt()` is used to retrieve the value of the option _name_ for
-the <<nng_tcp.5#,TCP connection>> _conn_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TCP connections are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_setopt.3tcp#,nng_tcp_setopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_listener.5.adoc b/docs/man/nng_tcp_listener.5.adoc
deleted file mode 100644
index ffa6fb53..00000000
--- a/docs/man/nng_tcp_listener.5.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_tcp_listener(5)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener - TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-typedef struct nng_tcp_dialer_s nng_tcp_dialer;
-----
-
-== DESCRIPTION
-
-(((TCP, listener)))
-An `nng_tcp_listener` is a handle to a TCP "`listener`", which is responsible
-for accepting connections (<<nng_tcp.5#,`nng_tcp`>> objects) from remote
-systems.
-
-NOTE: The `nng_tcp_listener` object is used for raw TCP connections, and
-should not be confused with a listener object created using the
-<<nng_tcp.7#,nng_tcp(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_tcp.7#,nng_tcp(7)>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept(3tcp)>>,
-<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc(3tcp)>>,
-<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close(3tcp)>>,
-<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free(3tcp)>>,
-<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt(3tcp)>>,
-<<nng_tcp_listener_listen.3tcp#,nng_tcp_listener_listen(3tcp)>>,
-<<nng_tcp_listener_setopt.3tcp#,nng_tcp_listener_setopt(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_dialer.5#,nng_tcp_dialer(5)>>,
-<<nng_tcp.7#,nng_tcp(7)>>
diff --git a/docs/man/nng_tcp_listener_accept.3tcp.adoc b/docs/man/nng_tcp_listener_accept.3tcp.adoc
deleted file mode 100644
index a50d709e..00000000
--- a/docs/man/nng_tcp_listener_accept.3tcp.adoc
+++ /dev/null
@@ -1,67 +0,0 @@
-= nng_tcp_listener_accept(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_accept - accept incoming TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_listener_accept(nng_tcp_listener *l, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_accept()` attempts to accept an incoming TCP connection
-from a remote peer, using the listener _l_.
-The operation is completed asynchronously, using _aio_.
-
-This operation can only be done after the listener is already bound to
-a TCP port and is <<nng_tcp_listener_listen.3tcp#,listening>>.
-
-If a connection is successfully established, the _aio_ will have the
-resulting <<nng_tcp.5#,`nng_tcp`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
-
-The address of the remote peer can be determined using the
-<<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>> option with the
-<<nng_tcp_getopt.3tcp#,`nng_tcp_getopt()`>> function on the
-returned <<nng_tcp.5#,`nng_tcp`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was aborted.
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_ECONNRESET`:: The TCP connection was reset by the peer.
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_ESTATE`:: The listener is not not listening.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc(3tcp)>>,
-<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close(3tcp)>>,
-<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free(3tcp)>>,
-<<nng_tcp_listener_listen.3tcp#,nng_tcp_listener_listen(3tcp)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_listener_alloc.3tcp.adoc b/docs/man/nng_tcp_listener_alloc.3tcp.adoc
deleted file mode 100644
index 718ac7a5..00000000
--- a/docs/man/nng_tcp_listener_alloc.3tcp.adoc
+++ /dev/null
@@ -1,51 +0,0 @@
-= nng_tcp_listener_alloc(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_alloc - allocate TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_listener_alloc(nng_tcp_listener *lp);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_alloc()` allocates a TCP listener, which can be used
-to accept incoming connections over TCP, and stores a pointer to it
-it in the location referenced by _lp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept(3tcp)>>,
-<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close(3tcp)>>,
-<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free(3tcp)>>,
-<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt(3tcp)>>,
-<<nng_tcp_listener_listen.3tcp#,nng_tcp_listener_listen(3tcp)>>,
-<<nng_tcp_listener_setopt.3tcp#,nng_tcp_listener_setopt(3tcp)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_listener_close.3tcp.adoc b/docs/man/nng_tcp_listener_close.3tcp.adoc
deleted file mode 100644
index a85d3675..00000000
--- a/docs/man/nng_tcp_listener_close.3tcp.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-= nng_tcp_listener_close(3tcp)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_close - close TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_listener_close(nng_tcp_listener *l);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_close()` function closes the supplied TCP listener _l_,
-but does not free the underlying resources associated with it.
-
-If any <<nng_tcp_listener_accept.3tcp#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-Furthermore any future accesses to the listener _l_ will also result in
-`NNG_ECLOSED`.
-
-NOTE: This function does not release the memory for the listener, so the
-application should still free the memory using
-<<nng_tcp_listener_free.3tcp#,`nng_tcp_listener_free()`>>
-once it is certain that nothing else is using it.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc(3tcp)>>,
-<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept(3tcp)>>,
-<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free(3tcp)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_listener_free.3tcp.adoc b/docs/man/nng_tcp_listener_free.3tcp.adoc
deleted file mode 100644
index a91a67b4..00000000
--- a/docs/man/nng_tcp_listener_free.3tcp.adoc
+++ /dev/null
@@ -1,51 +0,0 @@
-= nng_tcp_listener_free(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_free - free TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_listener_free(nng_tcp_listener *l);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_free()` function closes the supplied TCP listener _l_,
-and frees the underlying resources associated with it.
-
-If any <<nng_tcp_listener_accept.3tcp#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _l_, as the memory backing it will be reclaimed for other uses.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc(3tcp)>>,
-<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close(3tcp)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_listener_getopt.3tcp.adoc b/docs/man/nng_tcp_listener_getopt.3tcp.adoc
deleted file mode 100644
index 29a34192..00000000
--- a/docs/man/nng_tcp_listener_getopt.3tcp.adoc
+++ /dev/null
@@ -1,69 +0,0 @@
-= nng_tcp_listener_getopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_getopt - get option from TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_listener_getopt(nng_tcp_listener *l, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_getopt()` is used to retrieve the value of the option _name_ for the <<nng_tcp_listener.5#,TCP listener>> _l_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TCP listeners are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_setopt.3tcp#,nng_tcp_listener_setopt(3tcp)>>,
-<<nng_tcp_getopt.3tcp#,nng_tcp_getopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>
-
diff --git a/docs/man/nng_tcp_listener_listen.3tcp.adoc b/docs/man/nng_tcp_listener_listen.3tcp.adoc
deleted file mode 100644
index a50caf38..00000000
--- a/docs/man/nng_tcp_listener_listen.3tcp.adoc
+++ /dev/null
@@ -1,71 +0,0 @@
-= nng_tcp_listener_listen(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_listen - bind listener to TCP port
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_listener_listen(nng_tcp_listener l, const nng_sockaddr *sa);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_listen()` attempts to bind the listener _l_
-to the local address specified by _sa_, which must be in the
-`NNG_AF_INET` or `NNG_AF_INET6` address family.
-
-This also sets the underlying port into passive mode, ready to
-accept an incoming connection, and established a listen queue
-for receiving incoming connections. (The queue depth is system
-specific, but typically 128.)
-
-The actual IPv4 or IPv6 address in _sa_ may refer either to a locally
-configured interface address, or to a zero-valued adddress to indicate
-that all interfaces on the system should be bound.
-
-The TCP port number may also be zero. In this case the system will
-choose a free TCP port at random, and use it.
-
-The chosen port number may be retrieved using the
-<<nng_options.5#,`NNG_OPT_LOCADDR`>> option with the
-<<nng_tcp_listener_getopt.3tcp#,`nng_tcp_listener_getopt()`>> function.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_EADDRINUSE`:: The address specified by _sa_ is already in use.
-`NNG_EADDRINVAL`:: The address specified by _sa_ is invalid or unavailable.
-`NNG_ECLOSED`:: The listener _l_ has been closed.
-`NNG_ESTATE`:: The listener _l_ is already bound.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept(3tcp)>>,
-<<nng_tcp_listener_alloc.3tcp#,nng_tcp_listener_alloc(3tcp)>>,
-<<nng_tcp_listener_close.3tcp#,nng_tcp_listener_close(3tcp)>>,
-<<nng_tcp_listener_free.3tcp#,nng_tcp_listener_free(3tcp)>>,
-<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt(3tcp)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_listener_setopt.3tcp.adoc b/docs/man/nng_tcp_listener_setopt.3tcp.adoc
deleted file mode 100644
index 7e69c472..00000000
--- a/docs/man/nng_tcp_listener_setopt.3tcp.adoc
+++ /dev/null
@@ -1,62 +0,0 @@
-= nng_tcp_listener_setopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_listener_setopt - set option on TCP listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_listener_setopt(nng_tcp_listener *l, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_listener_setopt()` is used to set the option _name_ for the
-<<nng_tcp_listener.5#,TCP listener>> _l_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TCP listeners are:
-
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp_listener_getopt.3tcp#,nng_tcp_listener_getopt(3tcp)>>,
-<<nng_tcp_setopt.3tcp#,nng_tcp_setopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_tcp_listener.5#,nng_tcp_listener(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>
diff --git a/docs/man/nng_tcp_send.3tcp.adoc b/docs/man/nng_tcp_send.3tcp.adoc
deleted file mode 100644
index 806dd9c0..00000000
--- a/docs/man/nng_tcp_send.3tcp.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= nng_tcp_send(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_send - send to TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-void nng_tcp_send(nng_tcp *conn, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_send()` function starts an asynchronous send over the
-TCP connection _conn_ from the scatter/gather vector located in the
-asynchronous I/O structure _aio_.
-
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
-called first, to set the scatter/gather vector for _aio_.
-
-This function returns immediately, with no return value.
-Completion of the operation is signaled via the _aio_, and the final
-result may be obtained via <<nng_aio_result.3#,`nng_aio_result()`>>.
-That result will either be zero or an error code.
-
-The I/O operation completes as soon as at least one byte has been
-sent, or an error has occurred.
-Therefore, the number of bytes sent may be less than requested.
-The actual number of bytes sent can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
-
-NOTE: While TCP has the notion of urgent (out-of-band) delivery, that is
-used by very few protocols and this API does not support it.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was canceled.
-`NNG_ECLOSED`:: The connection was closed.
-`NNG_ECONNRESET`:: The peer closed the connection.
-`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector.
-`NNG_ENOMEM`:: Insufficient free memory to perform the operation.
-`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_tcp_close.3tcp#,nng_tcp_close(3tcp)>>,
-<<nng_tcp_recv.3tcp#,nng_tcp_recv(3tcp)>>,
-<<nng_tcp.5#,nng_tcp(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_tcp_setopt.3tcp.adoc b/docs/man/nng_tcp_setopt.3tcp.adoc
deleted file mode 100644
index b47bf62e..00000000
--- a/docs/man/nng_tcp_setopt.3tcp.adoc
+++ /dev/null
@@ -1,61 +0,0 @@
-= nng_tcp_setopt(3tcp)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tcp_setopt - set option on TCP connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
-
-int nng_tcp_setopt(nng_tcp *conn, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tcp_setopt()` is used to set the option _name_ for the
-<<nng_tcp.5#,TCP connection>> _conn_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TCP
-connections are:
-
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_tcp_getopt.3tcp#,nng_tcp_getopt(3tcp)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tls_dialer.5.adoc b/docs/man/nng_tls_dialer.5.adoc
deleted file mode 100644
index 86c44cea..00000000
--- a/docs/man/nng_tls_dialer.5.adoc
+++ /dev/null
@@ -1,51 +0,0 @@
-= nng_tls_dialer(5)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_dialer - TLS dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-typedef struct nng_tls_dialer_s nng_tls_dialer;
-----
-
-== DESCRIPTION
-
-(((TLS, dialer)))
-An `nng_tls_dialer` is a handle to a TLS "`dialer`", which is responsible for
-creating connections (<<nng_tls.5#,`nng_tls`>> objects) by connecting to
-remote systems.
-
-NOTE: The `nng_tls_dialer` object is used for raw IPC connections, and
-should not be confused with a dialer object created using the
-<<nng_tls.7#,nng_tls(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_tls.7#,nng_tls(7)>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_tls_dialer_alloc.3tls#,nng_tls_dialer_alloc(3tls)>>,
-<<nng_tls_dialer_close.3tls#,nng_tls_dialer_close(3tls)>>,
-<<nng_tls_dialer_dial.3tls#,nng_tls_dialer_dial(3tls)>>,
-<<nng_tls_dialer_free.3tls#,nng_tls_dialer_free(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>,
-<<nng_tls.7#,nng_tls(7)>>
diff --git a/docs/man/nng_tls_dialer_alloc.3tls.adoc b/docs/man/nng_tls_dialer_alloc.3tls.adoc
deleted file mode 100644
index 6a59eaee..00000000
--- a/docs/man/nng_tls_dialer_alloc.3tls.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_tls_dialer_alloc(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_dialer_alloc - allocate TLS dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_dialer_alloc(nng_tls_dialer *dp);
-----
-
-== DESCRIPTION
-
-The `nng_tls_dialer_alloc()` allocates a TLS dialer, which can be used
-to create outgoing connections over TLS, and stores a pointer to it
-it in the location referenced by _dp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_ENOTSUP`:: TLS support not configured in library.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_close.3tls#,nng_tls_dialer_close(3tls)>>,
-<<nng_tls_dialer_dial.3tls#,nng_tls_dialer_dial(3tls)>>,
-<<nng_tls_dialer_free.3tls#,nng_tls_dialer_free(3tls)>>,
-<<nng_tls_dialer_getopt.3tls#,nng_tls_dialer_getopt(3tls)>>,
-<<nng_tls_dialer_setopt.3tls#,nng_tls_dialer_setopt(3tls)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>
diff --git a/docs/man/nng_tls_dialer_getopt.3tls.adoc b/docs/man/nng_tls_dialer_getopt.3tls.adoc
deleted file mode 100644
index 6790092f..00000000
--- a/docs/man/nng_tls_dialer_getopt.3tls.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= nng_tls_dialer_getopt(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_dialer_getopt - get option from TLS dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_getopt(nng_tls_dialer *d, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tls_dialer_getopt()` is used to retrieve the value of the option _name_
-for the <<nng_tls_dialer.5#,TLS dialer>> _d_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TLS dialers are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CONFIG,`NNG_OPT_TLS_CONFIG`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_setopt.3tls#,nng_tls_dialer_setopt(3tls)>>,
-<<nng_tls_getopt.3tls#,nng_tls_getopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_config.5#,nng_tls_config(5)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
-
diff --git a/docs/man/nng_tls_dialer_setopt.3tls.adoc b/docs/man/nng_tls_dialer_setopt.3tls.adoc
deleted file mode 100644
index e7999c5b..00000000
--- a/docs/man/nng_tls_dialer_setopt.3tls.adoc
+++ /dev/null
@@ -1,69 +0,0 @@
-= nng_tls_dialer_setopt(3tls)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_dialer_setopt - set option on TLS dialer
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_dialer_setopt(nng_tls_dialer *d, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tls_dialer_setopt()` is used to set the option _name_ for the
-<<nng_tls_dialer.5#,TLS dialer>> _d_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TLS dialers are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_AUTH_MODE,`NNG_OPT_TLS_AUTH_MODE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CA_FILE,`NNG_OPT_TLS_CA_FILE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CERT_KEY_FILE,`NNG_OPT_TLS_CERT_KEY_FILE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CONFIG,`NNG_OPT_TLS_CONFIG`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_SERVER_NAME,`NNG_OPT_TLS_SERVER_NAME`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_dialer_getopt.3tls#,nng_tls_dialer_getopt(3tls)>>,
-<<nng_tls_setopt.3tls#,nng_tls_setopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
diff --git a/docs/man/nng_tls_getopt.3tls.adoc b/docs/man/nng_tls_getopt.3tls.adoc
deleted file mode 100644
index 87c8287c..00000000
--- a/docs/man/nng_tls_getopt.3tls.adoc
+++ /dev/null
@@ -1,70 +0,0 @@
-= nng_tls_getopt(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_getopt - get option from TLS connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_getopt(nng_tls *conn, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tls_getopt()` is used to retrieve the value of the option _name_ for
-the <<nng_tls.5#,TLS connection>> _conn_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TLS connections are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_VERIFIED,`NNG_OPT_TLS_VERIFIED`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_setopt.3tls#,nng_tls_setopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tls.5#,nng_tlsp(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
diff --git a/docs/man/nng_tls_listener.5.adoc b/docs/man/nng_tls_listener.5.adoc
deleted file mode 100644
index 6854aa57..00000000
--- a/docs/man/nng_tls_listener.5.adoc
+++ /dev/null
@@ -1,53 +0,0 @@
-= nng_tls_listener(5)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener - TLS listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-typedef struct nng_tls_dialer_s nng_tls_dialer;
-----
-
-== DESCRIPTION
-
-(((TLS, listener)))
-An `nng_tls_listener` is a handle to a TLS "`listener`", which is responsible
-for accepting connections (<<nng_tls.5#,`nng_tls`>> objects) from remote
-systems.
-
-NOTE: The `nng_tls_listener` object is used for raw TLS over TCP connections, and
-should not be confused with a listener object created using the
-<<nng_tls.7#,nng_tls(7)>> transport.
-
-TIP: Most NNG applications should not use this, but instead use the
-<<nng_tls.7#,nng_tls(7)>> transport instead.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_tls_listener_accept.3tls#,nng_tls_listener_accept(3tls)>>,
-<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc(3tls)>>,
-<<nng_tls_listener_close.3tls#,nng_tls_listener_close(3tls)>>,
-<<nng_tls_listener_free.3tls#,nng_tls_listener_free(3tls)>>,
-<<nng_tls_listener_getopt.3tls#,nng_tls_listener_getopt(3tls)>>,
-<<nng_tls_listener_listen.3tls#,nng_tls_listener_listen(3tls)>>,
-<<nng_tls_listener_setopt.3tls#,nng_tls_listener_setopt(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_dialer.5#,nng_tls_dialer(5)>>,
-<<nng_tls.7#,nng_tls(7)>>
diff --git a/docs/man/nng_tls_listener_accept.3tls.adoc b/docs/man/nng_tls_listener_accept.3tls.adoc
deleted file mode 100644
index 5d9b3952..00000000
--- a/docs/man/nng_tls_listener_accept.3tls.adoc
+++ /dev/null
@@ -1,70 +0,0 @@
-= nng_tls_listener_accept(3tls)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_accept - accept incoming TLS connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-void nng_tls_listener_accept(nng_tls_listener *l, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_accept()` attempts to accept an incoming TLS connection
-from a remote peer, using the listener _l_.
-The operation is completed asynchronously, using _aio_.
-
-This operation can only be done after the listener is already bound to
-a TCP port and is <<nng_tls_listener_listen.3tls#,listening>>.
-
-If a connection is successfully established, the _aio_ will have the
-resulting <<nng_tls.5#,`nng_tls`>> stored as its first output.
-(See <<nng_aio_get_output.3#,`nng_aio_get_output()`>>.)
-
-The address of the remote peer can be determined using the
-<<nng_options.5#NNG_OPT_REMADDR,`NNG_OPT_REMADDR`>> option with the
-<<nng_tls_getopt.3tls#,`nng_tls_getopt()`>> function on the
-returned <<nng_tls.5#,`nng_tls`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was aborted.
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_ECONNRESET`:: The connection was reset by the peer.
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_ESTATE`:: The listener is not not listening.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc(3tls)>>,
-<<nng_tls_listener_close.3tls#,nng_tls_listener_close(3tls)>>,
-<<nng_tls_listener_free.3tls#,nng_tls_listener_free(3tls)>>,
-<<nng_tls_listener_listen.3tls#,nng_tls_listener_listen(3tls)>>,
-<<nng_aio.5#,nng_aio(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
diff --git a/docs/man/nng_tls_listener_alloc.3tls.adoc b/docs/man/nng_tls_listener_alloc.3tls.adoc
deleted file mode 100644
index 88c4981a..00000000
--- a/docs/man/nng_tls_listener_alloc.3tls.adoc
+++ /dev/null
@@ -1,53 +0,0 @@
-= nng_tls_listener_alloc(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_alloc - allocate TLS listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_listener_alloc(nng_tls_listener *lp);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_alloc()` allocates a TLS listener, which can be used
-to accept incoming connections over TLS, and stores a pointer to it
-it in the location referenced by _lp_.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ENOMEM`:: Insufficient free memory exists.
-`NNG_ENOTSUP`:: TLS support not configured in library.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_accept.3tls#,nng_tls_listener_accept(3tls)>>,
-<<nng_tls_listener_close.3tls#,nng_tls_listener_close(3tls)>>,
-<<nng_tls_listener_free.3tls#,nng_tls_listener_free(3tls)>>,
-<<nng_tls_listener_getopt.3tls#,nng_tls_listener_getopt(3tls)>>,
-<<nng_tls_listener_listen.3tls#,nng_tls_listener_listen(3tls)>>,
-<<nng_tls_listener_setopt.3tls#,nng_tls_listener_setopt(3tls)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>
diff --git a/docs/man/nng_tls_listener_free.3tls.adoc b/docs/man/nng_tls_listener_free.3tls.adoc
deleted file mode 100644
index 067a803a..00000000
--- a/docs/man/nng_tls_listener_free.3tls.adoc
+++ /dev/null
@@ -1,52 +0,0 @@
-= nng_tls_listener_free(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_free - free TLS listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-void nng_tls_listener_free(nng_tls_listener *l);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_free()` function closes the supplied TLS listener _l_,
-and frees the underlying resources associated with it.
-
-If any <<nng_tls_listener_accept.3tls#,accept>> operations using _l_
-are in progress, they will be terminated with an `NNG_ECLOSED` error condition.
-
-WARNING: It is important that the application ensure that no further accesses
-are made to _l_, as the memory backing it will be reclaimed for other uses.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-None.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc(3tls)>>,
-<<nng_tls_listener_close.3tls#,nng_tls_listener_close(3tls)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>
diff --git a/docs/man/nng_tls_listener_getopt.3tls.adoc b/docs/man/nng_tls_listener_getopt.3tls.adoc
deleted file mode 100644
index 45abda1b..00000000
--- a/docs/man/nng_tls_listener_getopt.3tls.adoc
+++ /dev/null
@@ -1,72 +0,0 @@
-= nng_tls_listener_getopt(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_getopt - get option from TLS listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_listener_getopt(nng_tls_listener *l, const char *name, void *data, size_t *sizep);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_getopt()` is used to retrieve the value of the option
-_name_ for the <<nng_tls_listener.5#,TLS listener>> _l_.
-The size of the buffer located at _data_ to receive the copy is passed by the
-caller at the location referenced by _sizep_.
-If this size is sufficient to hold the entire object, the object is copied into
-the buffer specified by _data_.
-In either event, the size of the source object (the amount of data copied,
-or that would have been copied if sufficient space were available) is stored
-at the location of _sizep_.
-
-=== Options
-
-The options specifically suppported for retrieval from TLS listeners are:
-
-* <<nng_options.5#NNG_OPT_LOCADDR,`NNG_OPT_LOCADDR`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CONFIG,`NNG_OPT_TLS_CONFIG`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The dialer is closed.
-`NNG_EINVAL`:: There was insufficient space to receive the object.
- The amount of data actually needed is returned in _sizep_.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EWRITEONLY`:: The option _name_ may not read.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_setopt.3tls#,nng_tls_listener_setopt(3tls)>>,
-<<nng_tls_getopt.3tls#,nng_tls_getopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
-
diff --git a/docs/man/nng_tls_listener_listen.3tls.adoc b/docs/man/nng_tls_listener_listen.3tls.adoc
deleted file mode 100644
index 4fd6bf18..00000000
--- a/docs/man/nng_tls_listener_listen.3tls.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= nng_tls_listener_listen(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_listen - bind listener to TLS port
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_listener_listen(nng_tls_listener l, const nng_sockaddr *sa);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_listen()` attempts to bind the listener _l_
-to the local address specified by _sa_, which must be in the
-`NNG_AF_INET` or `NNG_AF_INET6` address family.
-
-This also sets the underlying port into passive mode, ready to
-accept an incoming connection, and established a listen queue
-for receiving incoming connections. (The queue depth is system
-specific, but typically 128.)
-
-The actual IPv4 or IPv6 address in _sa_ may refer either to a locally
-configured interface address, or to a zero-valued adddress to indicate
-that all interfaces on the system should be bound.
-
-The TCP port number may also be zero. In this case the system will
-choose a free TCP port at random, and use it.
-
-The chosen port number may be retrieved using the
-<<nng_options.5#,`NNG_OPT_LOCADDR`>> option with the
-<<nng_tls_listener_getopt.3tls#,`nng_tls_listener_getopt()`>> function.
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_EADDRINUSE`:: The address specified by _sa_ is already in use.
-`NNG_EADDRINVAL`:: The address specified by _sa_ is invalid or unavailable.
-`NNG_ECLOSED`:: The listener _l_ has been closed.
-`NNG_ECRYPTO`:: Cryptographic or certificate error.
-`NNG_ESTATE`:: The listener _l_ is already bound.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_accept.3tls#,nng_tls_listener_accept(3tls)>>,
-<<nng_tls_listener_alloc.3tls#,nng_tls_listener_alloc(3tls)>>,
-<<nng_tls_listener_close.3tls#,nng_tls_listener_close(3tls)>>,
-<<nng_tls_listener_free.3tls#,nng_tls_listener_free(3tls)>>,
-<<nng_tls_listener_getopt.3tls#,nng_tls_listener_getopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_sockaddr.5#,nng_sockaddr(5)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>
diff --git a/docs/man/nng_tls_listener_setopt.3tls.adoc b/docs/man/nng_tls_listener_setopt.3tls.adoc
deleted file mode 100644
index 7254fddb..00000000
--- a/docs/man/nng_tls_listener_setopt.3tls.adoc
+++ /dev/null
@@ -1,67 +0,0 @@
-= nng_tls_listener_setopt(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_listener_setopt - set option on TLS listener
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_listener_setopt(nng_tls_listener *l, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tls_listener_setopt()` is used to set the option _name_ for the
-<<nng_tls_listener.5#,TLS listener>> _l_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TLS listeners are:
-
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_AUTH_MODE,`NNG_OPT_TLS_AUTH_MODE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CA_FILE,`NNG_OPT_TLS_CA_FILE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CERT_KEY_FILE,`NNG_OPT_TLS_CERT_KEY_FILE`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_CONFIG,`NNG_OPT_TLS_CONFIG`>>
-* <<nng_tls_options.5#NNG_OPT_TLS_SERVER_NAME,`NNG_OPT_TLS_SERVER_NAME`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The listener is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_listener_getopt.3tls#,nng_tls_listener_getopt(3tls)>>,
-<<nng_tls_setopt.3tls#,nng_tls_setopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_listener.5#,nng_tls_listener(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
diff --git a/docs/man/nng_tls_recv.3tls.adoc b/docs/man/nng_tls_recv.3tls.adoc
deleted file mode 100644
index 39362a13..00000000
--- a/docs/man/nng_tls_recv.3tls.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= nng_tls_recv(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_recv - receive from TLS connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-void nng_tls_recv(nng_tls *conn, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tls_recv()` function starts an asynchronous receive from the
-TLS connection _conn_, into the scatter/gather vector located in the
-asynchronous I/O structure _aio_.
-
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
-called first, to set the scatter/gather vector for _aio_.
-
-This function returns immediately, with no return value.
-Completion of the operation is signaled via the _aio_,
-and the final result may be obtained via
-<<nng_aio_result.3#,`nng_aio_result()`>>.
-That result will either be zero or an error code.
-
-The I/O operation completes as soon as at least one byte has been
-received, or an error has occurred.
-Therefore, the number of bytes read may be less than requested.
-The actual number of bytes read can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was canceled.
-`NNG_ECLOSED`:: The connection was closed.
-`NNG_ECRYPTO`:: Cryptographic or certificate error.
-`NNG_ECONNRESET`:: The peer closed the connection.
-`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector.
-`NNG_ENOMEM`:: Insufficient free memory to perform the operation.
-`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_close.3tls#,nng_tls_close(3tls)>>,
-<<nng_tls_send.3tls#,nng_tls_send(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>
diff --git a/docs/man/nng_tls_send.3tls.adoc b/docs/man/nng_tls_send.3tls.adoc
deleted file mode 100644
index a82c6557..00000000
--- a/docs/man/nng_tls_send.3tls.adoc
+++ /dev/null
@@ -1,72 +0,0 @@
-= nng_tls_send(3tls)
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_send - send to TLS connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-void nng_tls_send(nng_tls *conn, nng_aio *aio);
-----
-
-== DESCRIPTION
-
-The `nng_tls_send()` function starts an asynchronous send over the
-TLS connection _conn_ from the scatter/gather vector located in the
-asynchronous I/O structure _aio_.
-
-NOTE: The <<nng_aio_set_iov.3#,`nng_aio_set_iov()`>> function must have been
-called first, to set the scatter/gather vector for _aio_.
-
-This function returns immediately, with no return value.
-Completion of the operation is signaled via the _aio_, and the final
-result may be obtained via <<nng_aio_result.3#,`nng_aio_result()`>>.
-That result will either be zero or an error code.
-
-The I/O operation completes as soon as at least one byte has been
-sent, or an error has occurred.
-Therefore, the number of bytes sent may be less than requested.
-The actual number of bytes sent can be determined with
-<<nng_aio_count.3#,`nng_aio_count()`>>.
-
-== RETURN VALUES
-
-None.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECANCELED`:: The operation was canceled.
-`NNG_ECLOSED`:: The connection was closed.
-`NNG_ECONNRESET`:: The peer closed the connection.
-`NNG_ECRYPTO`:: Cryptographic or certificate error.
-`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector.
-`NNG_ENOMEM`:: Insufficient free memory to perform the operation.
-`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_aio_alloc.3#,nng_aio_alloc(3)>>,
-<<nng_aio_count.3#,nng_aio_count(3)>>,
-<<nng_aio_result.3#,nng_aio_result(3)>>,
-<<nng_aio_set_iov.3#,nng_aio_set_iov(3)>>,
-<<nng_tls_close.3tls#,nng_tls_close(3tls)>>,
-<<nng_tls_recv.3tls#,nng_tls_recv(3tls)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_tls_setopt.3tls.adoc b/docs/man/nng_tls_setopt.3tls.adoc
deleted file mode 100644
index 3ba4a979..00000000
--- a/docs/man/nng_tls_setopt.3tls.adoc
+++ /dev/null
@@ -1,61 +0,0 @@
-= nng_tls_setopt(3tls)
-//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-// Copyright 2019 Devolutions <info@devolutions.net>
-//
-// This document 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.
-//
-
-== NAME
-
-nng_tls_setopt - set option on TLS connection
-
-== SYNOPSIS
-
-[source, c]
-----
-#include <nng/nng.h>
-#include <nng/supplemental/tls/tls.h>
-
-int nng_tls_setopt(nng_tls *conn, const char *name, const void *data, size_t size);
-----
-
-== DESCRIPTION
-
-The `nng_tls_setopt()` is used to set the option _name_ for the
-<<nng_tls.5#,TLS connection>> _conn_.
-The value to set is copied from _data_, which should be _size_ bytes
-in length.
-
-=== Options
-
-The options specifically suppported for modification on TLS connections are:
-
-* <<nng_tcp_options.5#NNG_OPT_TCP_KEEPALIVE,`NNG_OPT_TCP_KEEPALIVE`>>
-* <<nng_tcp_options.5#NNG_OPT_TCP_NODELAY,`NNG_OPT_TCP_NODELAY`>>
-
-== RETURN VALUES
-
-This function returns 0 on success, and non-zero otherwise.
-
-== ERRORS
-
-[horizontal]
-`NNG_ECLOSED`:: The connection _conn_ is closed.
-`NNG_EINVAL`:: Either _data_ or _size_ are invalid.
-`NNG_ENOTSUP`:: The option _name_ is not supported.
-`NNG_EREADONLY`:: The option _name_ may not be modified.
-
-== SEE ALSO
-
-[.text-left]
-<<nng_strerror.3#,nng_strerror(3)>>,
-<<nng_tls_getopt.3tls#,nng_tls_getopt(3tls)>>,
-<<nng_options.5#,nng_options(5)>>,
-<<nng_tcp_options.5#,nng_tcp_options(5)>>,
-<<nng_tls.5#,nng_tls(5)>>,
-<<nng_tls_options.5#,nng_tls_options(5)>>
diff --git a/include/nng/nng.h b/include/nng/nng.h
index 3063a652..eb50599a 100644
--- a/include/nng/nng.h
+++ b/include/nng/nng.h
@@ -788,6 +788,48 @@ enum nng_flag_enum {
// or even if processes can use IPC across jail boundaries.)
#define NNG_OPT_IPC_PEER_ZONEID "ipc:peer-zoneid"
+// WebSocket Options.
+
+// NNG_OPT_WS_REQUEST_HEADERS is a string containing the
+// request headers, formatted as CRLF terminated lines.
+#define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers"
+
+// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the
+// response headers, formatted as CRLF terminated lines.
+#define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers"
+
+// NNG_OPT_WS_REQUEST_HEADER is a prefix, for a dynamic
+// property name. This allows direct access to any named header.
+// Concatenate this with the name of the property (case is not sensitive).
+// Only the first such header is returned.
+#define NNG_OPT_WS_RESPONSE_HEADER "ws:response-header:"
+
+// NNG_OPT_WS_RESPONSE_HEADER is like NNG_OPT_REQUEST_HEADER, but used for
+// accessing the request headers.
+#define NNG_OPT_WS_REQUEST_HEADER "ws:request-header:"
+
+// NNG_OPT_WS_REQUEST_URI is used to obtain the URI sent by the client.
+// This can be useful when a handler supports an entire directory tree.
+#define NNG_OPT_WS_REQUEST_URI "ws:request-uri"
+
+// NNG_OPT_WS_TXFRAMESZ is used to configure the fragmentation size
+// used for frames. This has a default value of 64k. Large values
+// are good for throughput, but penalize latency. They also require
+// additional buffering on the peer. This value must not be larger
+// than what the peer will accept, and unfortunately there is no way
+// to negotiate this.
+#define NNG_OPT_WS_SENDMAXFRAME "ws:txframe-max"
+
+// NNG_OPT_WS_RXFRAMESZ is the largest frame we will accept. This should
+// probably not be larger than NNG_OPT_RECVMAXSZ. If the sender attempts
+// to send more data than this in a single message, it will be dropped.
+#define NNG_OPT_WS_RECVMAXFRAME "ws:rxframe-max"
+
+// NNG_OPT_WS_PROTOCOL is the "websocket subprotocol" -- it's a string.
+// This is also known as the Sec-WebSocket-Protocol header. It is treated
+// specially. This is part of the websocket handshake.
+#define NNG_OPT_WS_PROTOCOL "ws:protocol"
+
// XXX: TBD: priorities, ipv4only
// Statistics. These are for informational purposes only, and subject
@@ -973,6 +1015,120 @@ NNG_DECL int nng_url_clone(nng_url **, const nng_url *);
// nng_version returns the library version as a human readable string.
NNG_DECL const char *nng_version(void);
+
+// nng_stream operations permit direct access to low level streams,
+// which can have a variety of uses. Internally most of the transports
+// are built on top of these. Streams are created by other dialers or
+// listeners. The API for creating dialers and listeners varies.
+
+typedef struct nng_stream nng_stream;
+typedef struct nng_stream_dialer nng_stream_dialer;
+typedef struct nng_stream_listener nng_stream_listener;
+
+NNG_DECL void nng_stream_free(nng_stream *);
+NNG_DECL void nng_stream_close(nng_stream *);
+NNG_DECL void nng_stream_send(nng_stream *, nng_aio *);
+NNG_DECL void nng_stream_recv(nng_stream *, nng_aio *);
+NNG_DECL int nng_stream_get(nng_stream *, const char *, void *, size_t *);
+NNG_DECL int nng_stream_get_bool(nng_stream *, const char *, bool *);
+NNG_DECL int nng_stream_get_int(nng_stream *, const char *, int *);
+NNG_DECL int nng_stream_get_ms(nng_stream *, const char *, nng_duration *);
+NNG_DECL int nng_stream_get_size(nng_stream *, const char *, size_t *);
+NNG_DECL int nng_stream_get_uint64(nng_stream *, const char *, uint64_t *);
+NNG_DECL int nng_stream_get_ptr(nng_stream *, const char *, void **);
+NNG_DECL int nng_stream_get_addr(nng_stream *, const char *, nng_sockaddr *);
+NNG_DECL int nng_stream_set(nng_stream *, const char *, const void *, size_t);
+NNG_DECL int nng_stream_set_bool(nng_stream *, const char *, bool);
+NNG_DECL int nng_stream_set_int(nng_stream *, const char *, int);
+NNG_DECL int nng_stream_set_ms(nng_stream *, const char *, nng_duration);
+NNG_DECL int nng_stream_set_size(nng_stream *, const char *, size_t);
+NNG_DECL int nng_stream_set_uint64(nng_stream *, const char *, uint64_t);
+NNG_DECL int nng_stream_set_string(nng_stream *, const char *, const char *);
+NNG_DECL int nng_stream_set_ptr(nng_stream *, const char *, void *);
+NNG_DECL int nng_stream_set_addr(
+ nng_stream *, const char *, const nng_sockaddr *);
+
+NNG_DECL int nng_stream_dialer_alloc(nng_stream_dialer **, const char *);
+NNG_DECL int nng_stream_dialer_alloc_url(
+ nng_stream_dialer **, const nng_url *);
+NNG_DECL void nng_stream_dialer_free(nng_stream_dialer *);
+NNG_DECL void nng_stream_dialer_close(nng_stream_dialer *);
+NNG_DECL void nng_stream_dialer_dial(nng_stream_dialer *, nng_aio *);
+NNG_DECL int nng_stream_dialer_set(
+ nng_stream_dialer *, const char *, const void *, size_t);
+NNG_DECL int nng_stream_dialer_get(
+ nng_stream_dialer *, const char *, void *, size_t *);
+NNG_DECL int nng_stream_dialer_get_bool(
+ nng_stream_dialer *, const char *, bool *);
+NNG_DECL int nng_stream_dialer_get_int(
+ nng_stream_dialer *, const char *, int *);
+NNG_DECL int nng_stream_dialer_get_ms(
+ nng_stream_dialer *, const char *, nng_duration *);
+NNG_DECL int nng_stream_dialer_get_size(
+ nng_stream_dialer *, const char *, size_t *);
+NNG_DECL int nng_stream_dialer_get_uint64(
+ nng_stream_dialer *, const char *, uint64_t *);
+NNG_DECL int nng_stream_dialer_get_ptr(
+ nng_stream_dialer *, const char *, void **);
+NNG_DECL int nng_stream_dialer_get_addr(
+ nng_stream_dialer *, const char *, nng_sockaddr *);
+NNG_DECL int nng_stream_dialer_set_bool(
+ nng_stream_dialer *, const char *, bool);
+NNG_DECL int nng_stream_dialer_set_int(nng_stream_dialer *, const char *, int);
+NNG_DECL int nng_stream_dialer_set_ms(
+ nng_stream_dialer *, const char *, nng_duration);
+NNG_DECL int nng_stream_dialer_set_size(
+ nng_stream_dialer *, const char *, size_t);
+NNG_DECL int nng_stream_dialer_set_uint64(
+ nng_stream_dialer *, const char *, uint64_t);
+NNG_DECL int nng_stream_dialer_set_string(
+ nng_stream_dialer *, const char *, const char *);
+NNG_DECL int nng_stream_dialer_set_ptr(
+ nng_stream_dialer *, const char *, void *);
+NNG_DECL int nng_stream_dialer_set_addr(
+ nng_stream_dialer *, const char *, const nng_sockaddr *);
+
+NNG_DECL int nng_stream_listener_alloc(nng_stream_listener **, const char *);
+NNG_DECL int nng_stream_listener_alloc_url(
+ nng_stream_listener **, const nng_url *);
+NNG_DECL void nng_stream_listener_free(nng_stream_listener *);
+NNG_DECL void nng_stream_listener_close(nng_stream_listener *);
+NNG_DECL int nng_stream_listener_listen(nng_stream_listener *);
+NNG_DECL void nng_stream_listener_accept(nng_stream_listener *, nng_aio *);
+NNG_DECL int nng_stream_listener_set(
+ nng_stream_listener *, const char *, const void *, size_t);
+NNG_DECL int nng_stream_listener_get(
+ nng_stream_listener *, const char *, void *, size_t *);
+NNG_DECL int nng_stream_listener_get_bool(
+ nng_stream_listener *, const char *, bool *);
+NNG_DECL int nng_stream_listener_get_int(
+ nng_stream_listener *, const char *, int *);
+NNG_DECL int nng_stream_listener_get_ms(
+ nng_stream_listener *, const char *, nng_duration *);
+NNG_DECL int nng_stream_listener_get_size(
+ nng_stream_listener *, const char *, size_t *);
+NNG_DECL int nng_stream_listener_get_uint64(
+ nng_stream_listener *, const char *, uint64_t *);
+NNG_DECL int nng_stream_listener_get_ptr(
+ nng_stream_listener *, const char *, void **);
+NNG_DECL int nng_stream_listener_get_addr(
+ nng_stream_listener *, const char *, nng_sockaddr *);
+NNG_DECL int nng_stream_listener_set_bool(
+ nng_stream_listener *, const char *, bool);
+NNG_DECL int nng_stream_listener_set_int(nng_stream_listener *, const char *, int);
+NNG_DECL int nng_stream_listener_set_ms(
+ nng_stream_listener *, const char *, nng_duration);
+NNG_DECL int nng_stream_listener_set_size(
+ nng_stream_listener *, const char *, size_t);
+NNG_DECL int nng_stream_listener_set_uint64(
+ nng_stream_listener *, const char *, uint64_t);
+NNG_DECL int nng_stream_listener_set_string(
+ nng_stream_listener *, const char *, const char *);
+NNG_DECL int nng_stream_listener_set_ptr(
+ nng_stream_listener *, const char *, void *);
+NNG_DECL int nng_stream_listener_set_addr(
+ nng_stream_listener *, const char *, const nng_sockaddr *);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/nng/supplemental/ipc/ipc.h b/include/nng/supplemental/ipc/ipc.h
deleted file mode 100644
index 372b384e..00000000
--- a/include/nng/supplemental/ipc/ipc.h
+++ /dev/null
@@ -1,133 +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.
-//
-
-#ifndef NNG_SUPPLEMENTAL_IPC_IPC_H
-#define NNG_SUPPLEMENTAL_IPC_IPC_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <nng/nng.h>
-#include <nng/transport/ipc/ipc.h> // For IPC option names.
-
-// This is our "public" IPC API. This allows applications to access
-// basic IPC functions, using our AIO framework. Most applications will
-// not need this. This supports both UNIX domain sockets (AF_LOCAL),
-// and Windows Named Pipes, depending on the underlying platform.
-
-// nng_ipc represents a single IPC connection. This is generally
-// a connected stream.
-typedef struct nng_ipc_s nng_ipc;
-
-// nng_ipc_dialer is a dialer object used to create outgoing connections.
-// This is a bit different than a typical BSD socket API, but doing it
-// helps keep the API orthogonal to the listener API.
-typedef struct nng_ipc_dialer_s nng_ipc_dialer;
-
-// nng_ipc_listener is a listener object. This is used to accept incoming
-// connections.
-typedef struct nng_ipc_listener_s nng_ipc_listener;
-
-// nng_ipc_close closes the connection, but does not release the
-// underlying object. Operations that may be pending on the connect,
-// as well as further operations, will result in NNG_ECLOSED.
-NNG_DECL void nng_ipc_close(nng_ipc *);
-
-// nng_ipc_free frees the IPC connection, closing it if it is open.
-// This is necessary to release the resources of the IPC object.
-// (It is an error to refer to the IPC object after this is called.)
-NNG_DECL void nng_ipc_free(nng_ipc *);
-
-// nng_ipc_send sends the data in the aio, which should be stored in
-// an iov for the message. Note that the iov in the aio may be modified,
-// so applications should not assume otherwise.
-NNG_DECL void nng_ipc_send(nng_ipc *, nng_aio *);
-
-// nng_ipc_recv receives data into the iov supplied. It is possible for
-// the callback to be executed with less data read than requested. (This
-// is actually pretty likely for bulk transfers.) The caller should update
-// the iov's and resubmit as needed.
-NNG_DECL void nng_ipc_recv(nng_ipc *, nng_aio *);
-
-// nng_ipc_getopt is used to get options. The options available are:
-//
-// NNG_OPT_REMADDR - nng_sockaddr for the connection.
-// NNG_OPT_LOCADD - nng_sockaddr for the connection.
-// NNG_OPT_IPC_PEER_UID - peer user ID (if available), uint64_t
-// NNG_OPT_IPC_PEER_GID - peer group ID (if available), uint64_t
-// NNG_OPT_IPC_PEER_ZONEID - peer zone ID (illumos/Solaris only), uint64_t
-NNG_DECL int nng_ipc_getopt(nng_ipc *, const char *, void *, size_t *);
-
-// nng_ipc_setopt is used to set options. There are presently no such
-// options defined for connections.
-NNG_DECL int nng_ipc_setopt(nng_ipc *, const char *, const void *, size_t);
-
-// nng_ipc_dialer_alloc is used to allocate an IPC dialer.
-NNG_DECL int nng_ipc_dialer_alloc(nng_ipc_dialer **);
-
-// nng_ipc_dialer_close closes the dialer, aborting any pending outbound
-// connection attempts (and preventing any new ones) with NNG_ECLOSED.
-// This does not free the resources associated with the dialer, so the
-// application should still call nng_ipc_dialer_free. Connections already
-// established by the dialer are unaffected by this call.
-NNG_DECL void nng_ipc_dialer_close(nng_ipc_dialer *);
-
-// nng_ipc_dialer_free is used to free the dialer. This implicitly calls
-// nng_ipc_dialer_close, then releases the resources associated with the
-// dialer. It is therefore an error for the application to attempt to use
-// the dialer after this call.
-NNG_DECL void nng_ipc_dialer_free(nng_ipc_dialer *);
-
-// nng_ipc_dialer_dial attempts to create a new connection (nng_ipc *)
-// may making an outbound connect call. If this succeeds, the aio
-// will return a suitable nng_ipc * in the first output of the aio.
-// (I.e. nng_aio_get_output(aio, 0).) The destination address to dial
-// is stored in the 2nd argument.
-NNG_DECL void nng_ipc_dialer_dial(
- nng_ipc_dialer *, const nng_sockaddr *, nng_aio *);
-
-// nng_ipc_listener_alloc creates a listener.
-NNG_DECL int nng_ipc_listener_alloc(nng_ipc_listener **);
-
-// nng_ipc_listener_close closes the listener, unbinding it from
-// any active path if it was previously bound with nng_ipc_listener_listen.
-// This does not completely release the resources associated with the
-// listener, so nng_ipc_listener_free should still be called.
-// Any pending accept calls will be aborted with NNG_ECLOSED, and any
-// future attempts will also result in NNG_ECLOSED. Connections already
-// established by this listener are unaffected by this call.
-NNG_DECL void nng_ipc_listener_close(nng_ipc_listener *);
-
-// nng_ipc_listener_free frees the listener. This causes any other
-// outstanding accept calls to return NNG_ECLOSED. The listener cannot
-// be used by the application after this is called. This implictly
-// includes a call to nng_ipc_listener_close().
-NNG_DECL void nng_ipc_listener_free(nng_ipc_listener *);
-
-// nng_ipc_listener_listen binds to the IPC address and arranges for
-// the IPC path to be created and bound. It does not accept any new
-// incoming connections. This operation is synchronous.
-NNG_DECL int nng_ipc_listener_listen(nng_ipc_listener *, const nng_sockaddr *);
-
-// nng_ipc_listener_accept accepts an incoming connection (creating an
-// nng_ipc * object), and returns it in the nng_aio as the first output
-// on success.
-NNG_DECL void nng_ipc_listener_accept(nng_ipc_listener *, nng_aio *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // NNG_SUPPLEMENTAL_IPC_IPC_H
diff --git a/include/nng/supplemental/tcp/tcp.h b/include/nng/supplemental/tcp/tcp.h
deleted file mode 100644
index 295006c7..00000000
--- a/include/nng/supplemental/tcp/tcp.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Copyright 2018 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
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#ifndef NNG_SUPPLEMENTAL_TCP_TCP_H
-#define NNG_SUPPLEMENTAL_TCP_TCP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <nng/nng.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.
-
-// nng_tcp represents a single TCP connection. This is generally
-// a connected stream.
-typedef struct nng_tcp_s nng_tcp;
-
-// nng_tcp_dialer is a dialer object used to create outgoing connections.
-// This is a bit different than a typical BSD socket API, but doing it
-// helps keep the API orthogonal to the listener API.
-typedef struct nng_tcp_dialer_s nng_tcp_dialer;
-
-// nng_tcp_listener is a listener object. This is used to accept incoming
-// connections.
-typedef struct nng_tcp_listener_s nng_tcp_listener;
-
-// nng_tcp_close closes the connection, but does not release the
-// underlying object. Operations that may be pending on the connect,
-// as well as further operations, will result in NNG_ECLOSED.
-NNG_DECL void nng_tcp_close(nng_tcp *);
-
-// nng_tcp_free frees the TCP connection, closing it if it is open.
-// This is necessary to release the resources of the TCP object.
-// (It is an error to refer to the TCP object after this is called.)
-NNG_DECL void nng_tcp_free(nng_tcp *);
-
-// nng_tcp_send sends the data in the aio, which should be stored in
-// an iov for the message. Note that the iov in the aio may be modified,
-// so applications should not assume otherwise.
-NNG_DECL void nng_tcp_send(nng_tcp *, nng_aio *);
-
-// nng_tcp_recv receives data into the iov supplied. It is possible for
-// the callback to be executed with less data read than requested. (This
-// is actually pretty likely for bulk transfers.) The caller should update
-// the iov's and resubmit as needed.
-NNG_DECL void nng_tcp_recv(nng_tcp *, nng_aio *);
-
-// nng_tcp_getopt is used to retrieve socket options, using the named
-// option values, like NNG_OPT_TCP_NODELAY or NNG_OPT_REMADDR.
-NNG_DECL int nng_tcp_getopt(nng_tcp *, const char *, void *, size_t *);
-
-// nng_tcp_setopt is used to set socket options, using the named
-// option values, like NNG_OPT_TCP_KEEPALIVE.
-NNG_DECL int nng_tcp_setopt(nng_tcp *, const char *, const void *, size_t);
-
-// nng_tcp_dialer_alloc is used to allocate a TCP dialer.
-NNG_DECL int nng_tcp_dialer_alloc(nng_tcp_dialer **);
-
-// nng_tcp_dialer_close closes the dialer, aborting any pending outbound
-// connection attempts (and preventing any new ones) with NNG_ECLOSED.
-// This does not free the resources associated with the dialer, so the
-// application should still call nng_tcp_dialer_free. Connections already
-// established by the dialer are unaffected by this call.
-NNG_DECL void nng_tcp_dialer_close(nng_tcp_dialer *);
-
-// nng_tcp_dialer_free is used to free the dialer. This implicitly calls
-// nng_tcp_dialer_close, then releases the resources associated with the
-// dialer. It is therefore an error for the application to attempt to use
-// the dialer after this call.
-NNG_DECL void nng_tcp_dialer_free(nng_tcp_dialer *);
-
-// nng_tcp_dialer_dial attempts to create a new connection (nng_tcp *)
-// may making an outbound connect call. If this succeeds, the aio
-// will return a suitable nng_tcp * in the first output of the aio.
-// (I.e. nng_aio_get_output(aio, 0).) The destination address to dial
-// is stored in the 2nd argument.
-NNG_DECL void nng_tcp_dialer_dial(
- nng_tcp_dialer *, const nng_sockaddr *, nng_aio *);
-
-// nng_tcp_dialer_getopt gets an option.
-NNG_DECL int nng_tcp_dialer_getopt(
- nng_tcp_dialer *, const char *, void *, size_t *);
-
-// nng_tcp_dialer_setopt sets an option. This can be done to set the
-// initial values of NNG_OPT_TCP_NODELAY or NNG_OPT_TCP_KEEPALIVE for
-// created connections, for example. Also, the NNG_OPT_LOCADDR can
-// be set, which sets the source address new connections will be
-// established from -- except that the port is ignored as it is always
-// randomly chosen.
-NNG_DECL int nng_tcp_dialer_setopt(
- nng_tcp_dialer *, const char *, const void *, size_t);
-
-// nng_tcp_listener_alloc creates a listener.
-NNG_DECL int nng_tcp_listener_alloc(nng_tcp_listener **);
-
-// nng_tcp_listener_close closes the listener, unbinding it from
-// any active ports if it was previously bound with nng_tcp_listener_listen.
-// This does not completely release the resources associated with the
-// listener, so nng_tcp_listener_free should still be called.
-// Any pending accept calls will be aborted with NNG_ECLOSED, and any
-// future attempts will also result in NNG_ECLOSED. Connections already
-// established by this listener are unaffected by this call.
-NNG_DECL void nng_tcp_listener_close(nng_tcp_listener *);
-
-// nng_tcp_listener_free frees the listener. This causes any other
-// outstanding accept calls to return NNG_ECLOSED. The listener cannot
-// be used by the application after this is called. This implictly
-// includes a call to nng_tcp_listener_close().
-NNG_DECL void nng_tcp_listener_free(nng_tcp_listener *);
-
-// nng_tcp_listener_listen binds to the TCP address and arranges for
-// the TCP port / address to be allocated. It does not accept any new
-// incoming connections. (The listenq depth is configured to some reasonable
-// default -- typically around 128.) This operation is synchronous.
-// A zero valued port may be supplied in the sockaddr, in which case
-// a follow up call to get the NNG_OPT_LOCADDR can be used to determine the
-// bound address.
-NNG_DECL int nng_tcp_listener_listen(nng_tcp_listener *, const nng_sockaddr *);
-
-// nng_tcp_listener_accept accepts an incoming connection (creating an
-// nng_tcp * object), and returns it in the nng_aio as the first output
-// on success.
-NNG_DECL void nng_tcp_listener_accept(nng_tcp_listener *, nng_aio *);
-
-// nng_tcp_listener_getopt gets an option. A good example of this is to
-// obtain the NNG_OPT_LOCADDR local address after starting the listener
-// on a wild card port (0).
-NNG_DECL int nng_tcp_listener_getopt(
- nng_tcp_listener *, const char *, void *, size_t *);
-
-// nng_tcp_listener_setopt sets an option. This can be done to set the
-// initial values of NNG_OPT_TCP_NODELAY or NNG_OPT_TCP_KEEPALIVE for
-// created connections, for example.
-NNG_DECL int nng_tcp_listener_setopt(
- nng_tcp_listener *, const char *, const void *, size_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // NNG_SUPPLEMENTAL_TCP_TCP_H
diff --git a/include/nng/supplemental/tls/tls.h b/include/nng/supplemental/tls/tls.h
index 496f02e2..5983f3b6 100644
--- a/include/nng/supplemental/tls/tls.h
+++ b/include/nng/supplemental/tls/tls.h
@@ -105,74 +105,6 @@ NNG_DECL int nng_tls_config_ca_file(nng_tls_config *, const char *);
NNG_DECL int nng_tls_config_cert_key_file(
nng_tls_config *, const char *, const char *);
-// The rest of the definitions in this file rely upon having support for the
-// TLS supplemental API enabled. If you don't have this configured in your
-// library, then your programs will not link.
-
-// nng_tls represents a TLS connection over TCP.
-typedef struct nng_tls_s nng_tls;
-
-// nng_tls_dialer is a dialer that creates TLS connections (nng_tls objects)
-// by establishing outgoing connections.
-typedef struct nng_tls_dialer_s nng_tls_dialer;
-
-// nng_tls_listener is a listener that creates TLS connections (nng_tls
-// objects) by accepting incoming connections.
-typedef struct nng_tls_listener_s nng_tls_listener;
-
-// nng_tls_close closes a TLS connection, without releasing the underlying
-// resources. Use nng_tls_free to release the resources.
-NNG_DECL void nng_tls_close(nng_tls *);
-
-// nng_tls_free frees a TLS connection, and will implicity also close the
-// connection if not already done so.
-NNG_DECL void nng_tls_free(nng_tls *);
-
-NNG_DECL void nng_tls_send(nng_tls *, nng_aio *);
-NNG_DECL void nng_tls_recv(nng_tls *, nng_aio *);
-
-NNG_DECL int nng_tls_getopt(nng_tls *, const char *, void *, size_t *);
-
-// nng_tls_dialer_alloc allocates a dialer that creates TLS connections
-// (nng_tls structures) by connecting to remote servers.
-NNG_DECL int nng_tls_dialer_alloc(nng_tls_dialer **);
-
-// nng_tls_dialer_close closes the dialer, but does not free it's resources.
-NNG_DECL void nng_tls_dialer_close(nng_tls_dialer *);
-
-// nng_tls_dialer_free frees the dialer, implicitly closing it as well.
-NNG_DECL void nng_tls_dialer_free(nng_tls_dialer *);
-
-// nng_tls_dialer_dial attempts to create a new connection (nng_tls object)
-// by dialing to the remote server specified in the aio. Note that the
-// TLS connection may be returned before the TLS handshake is complete.
-// The remote server will only be verified if a server name has been configured
-// with the NNG_OPT_TLS_SERVER_NAME option (using nng_tls_dialer_setopt).
-NNG_DECL void nng_tls_dialer_dial(
- nng_tls_dialer *, const nng_sockaddr *, nng_aio *);
-
-// nng_tls_dialer_getopt returns options from the dialer.
-NNG_DECL int nng_tls_dialer_getopt(
- nng_tls_dialer *, const char *, void *, size_t *);
-
-// nng_tls_dialer_setopt sets options on the dialer. Options may include
-// NNG_OPT_TLS_CONFIG, as well as various other NNG_OPT_TLS_ options and
-// the TCP options that are valid for TCP dialers as well.
-NNG_DECL int nng_tls_dialer_setopt(
- nng_tls_dialer *, const char *, const void *, size_t);
-
-NNG_DECL int nng_tls_listener_alloc(nng_tls_listener **);
-NNG_DECL void nng_tls_listener_close(nng_tls_listener *);
-NNG_DECL void nng_tls_listener_free(nng_tls_listener *);
-NNG_DECL int nng_tls_listener_listen(nng_tls_listener *, const nng_sockaddr *);
-NNG_DECL void nng_tls_listener_accept(nng_tls_listener *, nng_aio *);
-
-NNG_DECL int nng_tls_listener_getopt(
- nng_tls_listener *, const char *, void *, size_t *);
-
-NNG_DECL int nng_tls_listener_setopt(
- nng_tls_listener *, const char *, const void *, size_t);
-
#ifdef __cplusplus
}
#endif
diff --git a/include/nng/transport/tcp/tcp.h b/include/nng/transport/tcp/tcp.h
index 6975109f..c2277e4b 100644
--- a/include/nng/transport/tcp/tcp.h
+++ b/include/nng/transport/tcp/tcp.h
@@ -13,6 +13,8 @@
// TCP transport. This is used for communication over TCP/IP.
+#include <nng/nng.h>
+
NNG_DECL int nng_tcp_register(void);
#endif // NNG_TRANSPORT_TCP_TCP_H
diff --git a/include/nng/transport/ws/websocket.h b/include/nng/transport/ws/websocket.h
index 8179beab..3d0d4fee 100644
--- a/include/nng/transport/ws/websocket.h
+++ b/include/nng/transport/ws/websocket.h
@@ -15,14 +15,6 @@
NNG_DECL int nng_ws_register(void);
-// NNG_OPT_WS_REQUEST_HEADERS is a string containing the
-// request headers, formatted as CRLF terminated lines.
-#define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers"
-
-// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the
-// response headers, formatted as CRLF terminated lines.
-#define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers"
-
// These aliases are for WSS naming consistency.
#define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS
#define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS
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
diff --git a/tests/ipcsupp.c b/tests/ipcsupp.c
index 41f6468d..bb7d92f7 100644
--- a/tests/ipcsupp.c
+++ b/tests/ipcsupp.c
@@ -12,46 +12,38 @@
#include <string.h>
#include <nng/nng.h>
-#include <nng/supplemental/ipc/ipc.h>
#include "convey.h"
#include "stubs.h"
-static uint8_t loopback[4] = { 127, 0, 0, 1 };
-static int num = 0;
+static int num = 0;
TestMain("Supplemental IPC", {
atexit(nng_fini);
Convey("We can create a dialer and listener", {
- nng_ipc_dialer * d;
- nng_ipc_listener *l;
- So(nng_ipc_dialer_alloc(&d) == 0);
- So(nng_ipc_listener_alloc(&l) == 0);
+ nng_stream_dialer * d;
+ nng_stream_listener *l;
+ char url[64];
+
+ snprintf(url, sizeof(url), "ipc:///tmp/ipcsupp_test%d", num);
+ num++;
+ So(nng_stream_dialer_alloc(&d, url) == 0);
+ So(nng_stream_listener_alloc(&l, url) == 0);
Reset({
- nng_ipc_listener_close(l);
- nng_ipc_dialer_close(d);
- nng_ipc_listener_free(l);
- nng_ipc_dialer_free(d);
+ nng_stream_listener_close(l);
+ nng_stream_dialer_close(d);
+ nng_stream_listener_free(l);
+ nng_stream_dialer_free(d);
});
- Convey("Listener listens (wildcard)", {
- nng_sockaddr sa;
- uint32_t ip;
-
- memcpy(&ip, loopback, 4);
-
- num++;
- sa.s_ipc.sa_family = NNG_AF_IPC;
- snprintf(sa.s_ipc.sa_path, sizeof(sa.s_ipc.sa_path),
- "/tmp/ipc_supp_test%d", num);
-
- So(nng_ipc_listener_listen(l, &sa) == 0);
+ Convey("Listener listens", {
+ So(nng_stream_listener_listen(l) == 0);
Convey("We can dial it", {
- nng_aio *daio = NULL;
- nng_aio *laio = NULL;
- nng_aio *maio = NULL;
- nng_ipc *c1 = NULL;
- nng_ipc *c2 = NULL;
+ nng_aio * daio = NULL;
+ nng_aio * laio = NULL;
+ nng_aio * maio = NULL;
+ nng_stream *c1 = NULL;
+ nng_stream *c2 = NULL;
So(nng_aio_alloc(&daio, NULL, NULL) == 0);
So(nng_aio_alloc(&laio, NULL, NULL) == 0);
@@ -61,17 +53,17 @@ TestMain("Supplemental IPC", {
nng_aio_free(daio);
nng_aio_free(laio);
if (c1 != NULL) {
- nng_ipc_close(c1);
- nng_ipc_free(c1);
+ nng_stream_close(c1);
+ nng_stream_free(c1);
}
if (c2 != NULL) {
- nng_ipc_close(c2);
- nng_ipc_free(c2);
+ nng_stream_close(c2);
+ nng_stream_free(c2);
}
});
- nng_ipc_dialer_dial(d, &sa, daio);
- nng_ipc_listener_accept(l, laio);
+ nng_stream_dialer_dial(d, daio);
+ nng_stream_listener_accept(l, laio);
nng_aio_wait(daio);
nng_aio_wait(laio);
@@ -117,8 +109,8 @@ TestMain("Supplemental IPC", {
iov.iov_buf = buf2;
iov.iov_len = 5;
nng_aio_set_iov(aio2, 1, &iov);
- nng_ipc_send(c1, aio1);
- nng_ipc_recv(c2, aio2);
+ nng_stream_send(c1, aio1);
+ nng_stream_recv(c2, aio2);
nng_aio_wait(aio1);
nng_aio_wait(aio2);
@@ -131,14 +123,15 @@ TestMain("Supplemental IPC", {
So(memcmp(buf1, buf2, 5) == 0);
Convey("Socket name matches", {
- size_t rsz = sizeof(sa2);
- So(nng_ipc_getopt(c2,
- NNG_OPT_LOCADDR, &sa2,
- &rsz) == 0);
+ So(nng_stream_get_addr(c2,
+ NNG_OPT_LOCADDR,
+ &sa2) == 0);
So(sa2.s_ipc.sa_family ==
NNG_AF_IPC);
So(strcmp(sa2.s_ipc.sa_path,
- sa.s_ipc.sa_path) == 0);
+ url +
+ strlen("ipc://")) ==
+ 0);
});
});
});
diff --git a/tests/resolv.c b/tests/resolv.c
index 954481b7..bcfb78a4 100644
--- a/tests/resolv.c
+++ b/tests/resolv.c
@@ -77,11 +77,11 @@ TestMain("Resolver", {
nng_sockaddr sa;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("google-public-dns-a.google.com", "80",
NNG_AF_INET, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So(sa.s_in.sa_family == NNG_AF_INET);
So(sa.s_in.sa_port == ntohs(80));
str = ip4tostr(&sa.s_in.sa_addr);
@@ -94,10 +94,10 @@ TestMain("Resolver", {
nng_sockaddr sa;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_udp_resolv("8.8.4.4", "69", NNG_AF_INET, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So(sa.s_in.sa_family == NNG_AF_INET);
So(sa.s_in.sa_port == ntohs(69));
str = ip4tostr(&sa.s_in.sa_addr);
@@ -110,10 +110,10 @@ TestMain("Resolver", {
nng_sockaddr sa;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("8.8.4.4", "80", NNG_AF_INET, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So(sa.s_in.sa_family == NNG_AF_INET);
So(sa.s_in.sa_port == ntohs(80));
str = ip4tostr(&sa.s_in.sa_addr);
@@ -135,10 +135,10 @@ TestMain("Resolver", {
}
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("::1", "80", NNG_AF_INET6, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So(sa.s_in6.sa_family == NNG_AF_INET6);
So(sa.s_in6.sa_port == ntohs(80));
str = ip6tostr(&sa.s_in6.sa_addr);
@@ -147,11 +147,9 @@ TestMain("Resolver", {
});
Convey("Name service names not supported", {
- nng_aio * aio;
- nng_sockaddr sa;
+ nng_aio *aio;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("8.8.4.4", "http", NNG_AF_INET, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == NNG_EADDRINVAL);
@@ -164,10 +162,10 @@ TestMain("Resolver", {
nng_sockaddr sa;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("localhost", "80", NNG_AF_INET, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So(sa.s_in.sa_family == NNG_AF_INET);
So(sa.s_in.sa_port == ntohs(80));
So(sa.s_in.sa_addr == ntohl(0x7f000001));
@@ -182,10 +180,10 @@ TestMain("Resolver", {
nng_sockaddr sa;
So(nng_aio_alloc(&aio, NULL, NULL) == 0);
- nng_aio_set_input(aio, 0, &sa);
nni_tcp_resolv("localhost", "80", NNG_AF_UNSPEC, 1, aio);
nng_aio_wait(aio);
So(nng_aio_result(aio) == 0);
+ nni_aio_get_sockaddr(aio, &sa);
So((sa.s_family == NNG_AF_INET) ||
(sa.s_family == NNG_AF_INET6));
switch (sa.s_family) {
diff --git a/tests/stubs.h b/tests/stubs.h
index c34bed7a..a8fa59e9 100644
--- a/tests/stubs.h
+++ b/tests/stubs.h
@@ -85,6 +85,15 @@ nosocket(nng_socket *s)
return (NNG_ENOTSUP);
}
+uint16_t
+test_htons(uint16_t in)
+{
+#ifdef NNG_LITTLE_ENDIAN
+ in = ((in >> 8) & 0xff) | ((in & 0xff) << 8);
+#endif
+ return (in);
+}
+
#ifndef NNG_HAVE_REQ0
#define nng_req0_open nosocket
#endif
diff --git a/tests/tcpsupp.c b/tests/tcpsupp.c
index 1f91a60c..e25383c5 100644
--- a/tests/tcpsupp.c
+++ b/tests/tcpsupp.c
@@ -11,52 +11,54 @@
#include <string.h>
#include <nng/nng.h>
-#include <nng/supplemental/tcp/tcp.h>
#include "convey.h"
#include "stubs.h"
-static uint8_t loopback[4] = { 127, 0, 0, 1 };
-
TestMain("Supplemental TCP", {
atexit(nng_fini);
Convey("We can create a dialer and listener", {
- nng_tcp_dialer * d;
- nng_tcp_listener *l;
- So(nng_tcp_dialer_alloc(&d) == 0);
- So(nng_tcp_listener_alloc(&l) == 0);
+ nng_stream_dialer * d = NULL;
+ nng_stream_listener *l = NULL;
Reset({
- nng_tcp_listener_close(l);
- nng_tcp_dialer_close(d);
- nng_tcp_listener_free(l);
- nng_tcp_dialer_free(d);
+ nng_stream_listener_free(l);
+ nng_stream_dialer_free(d);
+ l = NULL;
+ d = NULL;
});
Convey("Listener listens (wildcard)", {
nng_sockaddr sa;
- uint32_t ip;
size_t sz;
-
- memcpy(&ip, loopback, 4);
-
- sa.s_in.sa_family = NNG_AF_INET;
- sa.s_in.sa_addr = ip;
- sa.s_in.sa_port = 0;
- sz = sizeof(sa);
-
- So(nng_tcp_listener_listen(l, &sa) == 0);
- So(nng_tcp_listener_getopt(
+ uint8_t ip[4];
+
+ So(nng_stream_listener_alloc(&l, "tcp://127.0.0.1") ==
+ 0);
+ So(nng_stream_listener_listen(l) == 0);
+
+ sz = sizeof(sa);
+ ip[0] = 127;
+ ip[1] = 0;
+ ip[2] = 0;
+ ip[3] = 1;
+ So(nng_stream_listener_get(
l, NNG_OPT_LOCADDR, &sa, &sz) == 0);
So(sz == sizeof(sa));
So(sa.s_in.sa_port != 0);
- So(sa.s_in.sa_addr == ip);
+ So(memcmp(&sa.s_in.sa_addr, ip, 4) == 0);
Convey("We can dial it", {
- nng_aio *daio = NULL;
- nng_aio *laio = NULL;
- nng_aio *maio = NULL;
- nng_tcp *c1 = NULL;
- nng_tcp *c2 = NULL;
-
+ nng_aio * daio = NULL;
+ nng_aio * laio = NULL;
+ nng_aio * maio = NULL;
+ nng_stream *c1 = NULL;
+ nng_stream *c2 = NULL;
+
+ char uri[64];
+ snprintf(uri, sizeof(uri),
+ "tcp://127.0.0.1:%d",
+ test_htons(sa.s_in.sa_port));
+
+ So(nng_stream_dialer_alloc(&d, uri) == 0);
So(nng_aio_alloc(&daio, NULL, NULL) == 0);
So(nng_aio_alloc(&laio, NULL, NULL) == 0);
So(nng_aio_alloc(&maio, NULL, NULL) == 0);
@@ -65,20 +67,22 @@ TestMain("Supplemental TCP", {
nng_aio_free(daio);
nng_aio_free(laio);
if (c1 != NULL) {
- nng_tcp_close(c1);
- nng_tcp_free(c1);
+ nng_stream_close(c1);
+ nng_stream_free(c1);
}
if (c2 != NULL) {
- nng_tcp_close(c2);
- nng_tcp_free(c2);
+ nng_stream_close(c2);
+ nng_stream_free(c2);
}
});
- nng_tcp_dialer_dial(d, &sa, daio);
- nng_tcp_listener_accept(l, laio);
+ nng_stream_dialer_dial(d, daio);
+ nng_stream_listener_accept(l, laio);
nng_aio_wait(daio);
+ So(nng_aio_result(daio) == 0);
nng_aio_wait(laio);
+ So(nng_aio_result(laio) == 0);
So(nng_aio_result(daio) == 0);
So(nng_aio_result(laio) == 0);
@@ -109,20 +113,20 @@ TestMain("Supplemental TCP", {
});
on = true;
- So(nng_tcp_setopt(c1,
+ So(nng_stream_set(c1,
NNG_OPT_TCP_NODELAY, &on,
sizeof(on)) == 0);
- So(nng_tcp_setopt(c2,
+ So(nng_stream_set(c2,
NNG_OPT_TCP_NODELAY, &on,
sizeof(on)) == 0);
- So(nng_tcp_setopt(c1,
+ So(nng_stream_set(c1,
NNG_OPT_TCP_KEEPALIVE, &on,
sizeof(on)) == 0);
on = false;
sz = sizeof(on);
- So(nng_tcp_getopt(c1,
+ So(nng_stream_get(c1,
NNG_OPT_TCP_NODELAY, &on,
&sz) == 0);
So(sz == sizeof(on));
@@ -130,7 +134,7 @@ TestMain("Supplemental TCP", {
on = false;
sz = sizeof(on);
- So(nng_tcp_getopt(c1,
+ So(nng_stream_get(c1,
NNG_OPT_TCP_KEEPALIVE, &on,
&sz) == 0);
So(sz == sizeof(on));
@@ -151,8 +155,8 @@ TestMain("Supplemental TCP", {
iov.iov_buf = buf2;
iov.iov_len = 5;
nng_aio_set_iov(aio2, 1, &iov);
- nng_tcp_send(c1, aio1);
- nng_tcp_recv(c2, aio2);
+ nng_stream_send(c1, aio1);
+ nng_stream_recv(c2, aio2);
nng_aio_wait(aio1);
nng_aio_wait(aio2);
@@ -166,26 +170,29 @@ TestMain("Supplemental TCP", {
Convey("Socket name matches", {
sz = sizeof(sa2);
- So(nng_tcp_getopt(c2,
+ So(nng_stream_get(c2,
NNG_OPT_LOCADDR, &sa2,
&sz) == 0);
So(sz == sizeof(sa2));
So(sa2.s_in.sa_family ==
NNG_AF_INET);
- So(sa2.s_in.sa_addr == ip);
+
+ So(sa2.s_in.sa_addr ==
+ sa.s_in.sa_addr);
So(sa2.s_in.sa_port ==
sa.s_in.sa_port);
});
Convey("Peer name matches", {
sz = sizeof(sa2);
- So(nng_tcp_getopt(c1,
+ So(nng_stream_get(c1,
NNG_OPT_REMADDR, &sa2,
&sz) == 0);
So(sz == sizeof(sa2));
So(sa2.s_in.sa_family ==
NNG_AF_INET);
- So(sa2.s_in.sa_addr == ip);
+ So(sa2.s_in.sa_addr ==
+ sa.s_in.sa_addr);
So(sa2.s_in.sa_port ==
sa.s_in.sa_port);
});