aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/man/CMakeLists.txt28
-rw-r--r--docs/man/libnng.3.adoc24
-rw-r--r--docs/man/man3tcp.desc5
-rw-r--r--docs/man/man3tcp.sect1
-rw-r--r--docs/man/nng_tcp.5.adoc69
-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.adoc48
-rw-r--r--docs/man/nng_tcp_dialer_close.3tcp.adoc58
-rw-r--r--docs/man/nng_tcp_dialer_dial.3tcp.adoc63
-rw-r--r--docs/man/nng_tcp_dialer_free.3tcp.adoc53
-rw-r--r--docs/man/nng_tcp_free.3tcp.adoc58
-rw-r--r--docs/man/nng_tcp_listener.5.adoc50
-rw-r--r--docs/man/nng_tcp_listener_accept.3tcp.adoc67
-rw-r--r--docs/man/nng_tcp_listener_alloc.3tcp.adoc49
-rw-r--r--docs/man/nng_tcp_listener_close.3tcp.adoc58
-rw-r--r--docs/man/nng_tcp_listener_free.3tcp.adoc52
-rw-r--r--docs/man/nng_tcp_listener_listen.3tcp.adoc66
-rw-r--r--docs/man/nng_tcp_peername.3tcp.adoc45
-rw-r--r--docs/man/nng_tcp_recv.3tcp.adoc74
-rw-r--r--docs/man/nng_tcp_send.3tcp.adoc73
-rw-r--r--docs/man/nng_tcp_set_keepalive.3tcp.adoc55
-rw-r--r--docs/man/nng_tcp_set_nodelay.3tcp.adoc56
-rw-r--r--docs/man/nng_tcp_sockname.3tcp.adoc45
-rw-r--r--include/nng/supplemental/tcp/tcp.h148
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/supplemental/tcp/CMakeLists.txt15
-rw-r--r--src/supplemental/tcp/tcp.c153
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/tcpsupp.c160
30 files changed, 1684 insertions, 0 deletions
diff --git a/docs/man/CMakeLists.txt b/docs/man/CMakeLists.txt
index 77efa1c8..db4e797e 100644
--- a/docs/man/CMakeLists.txt
+++ b/docs/man/CMakeLists.txt
@@ -290,6 +290,26 @@ if (NNG_ENABLE_DOC)
nng_thread_destroy
)
+ set(NNG_MAN3TCP
+ nng_tcp_close
+ nng_tcp_free
+ nng_tcp_dialer_alloc
+ nng_tcp_dialer_close
+ nng_tcp_dialer_dial
+ nng_tcp_dialer_free
+ nng_tcp_listener_accept
+ nng_tcp_listener_alloc
+ nng_tcp_listener_close
+ nng_tcp_listener_free
+ nng_tcp_listener_listen
+ nng_tcp_peername
+ nng_tcp_recv
+ nng_tcp_send
+ nng_tcp_set_keepalive
+ nng_tcp_set_nodelay
+ nng_tcp_sockname
+ )
+
set(NNG_MAN3TLS
nng_tls_config_alloc
nng_tls_config_auth_mode
@@ -320,6 +340,10 @@ if (NNG_ENABLE_DOC)
nng_sockaddr_zt
nng_socket
nng_stat
+
+ nng_tcp
+ nng_tcp_dialer
+ nng_tcp_listener
)
set(NNG_MAN7
@@ -362,6 +386,10 @@ if (NNG_ENABLE_DOC)
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 25e8b08d..5d5f5ef0 100644
--- a/docs/man/libnng.3.adoc
+++ b/docs/man/libnng.3.adoc
@@ -279,6 +279,30 @@ as a convenience to aid in creating portable applications.
|===
+=== Supplemental TCP
+
+|===
+|<<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_free.3tcp#,nng_tcp_free()>>|free 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_listen.3tcp#,nng_tcp_listener_listen()>>|bind TCP listener to port
+|<<nng_tcp_peername.3tcp#,nng_tcp_peername()>>|get TCP peer socket address
+|<<nng_tcp_recv.3tcp#,nng_tcp_recv()>>|receive from TCP connection
+|<<nng_tcp_send.3tcp#,nng_tcp_send()>>|send to TCP connection
+|<<nng_tcp_sockname.3tcp#,nng_tcp_sockname()>>|get TCP local socket address
+|<<nng_tcp_set_keepalive.3tcp#,nng_tcp_set_keepalive()>>|enable or disable TCP keepalives
+|<<nng_tcp_set_nodelay.3tcp#,nng_tcp_set_nodelay()>>|disable Nagle's algorithm
+
+|
+
+|===
=== HTTP Support
The library may be configured with support for HTTP, and this will
diff --git a/docs/man/man3tcp.desc b/docs/man/man3tcp.desc
new file mode 100644
index 00000000..c38f257e
--- /dev/null
+++ b/docs/man/man3tcp.desc
@@ -0,0 +1,5 @@
+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/man3tcp.sect b/docs/man/man3tcp.sect
new file mode 100644
index 00000000..ed1b8306
--- /dev/null
+++ b/docs/man/man3tcp.sect
@@ -0,0 +1 @@
+Supplemental TCP Functions
diff --git a/docs/man/nng_tcp.5.adoc b/docs/man/nng_tcp.5.adoc
new file mode 100644
index 00000000..10a3c2f3
--- /dev/null
+++ b/docs/man/nng_tcp.5.adoc
@@ -0,0 +1,69 @@
+= nng_tcp(5)
+//
+// 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 - TCP connection
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+typedef struct nng_tcp_s nng_tcp;
+----
+
+== DESCRIPTION
+
+An `nng_tcp` (((TCP connection))) represents a connected stream.
+TCP stream objects can be used to send or receive data.
+
+NOTE: The `nng_tcp` object is used for raw TCP connections, and
+should not be confused with a pipe 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.
+
+These objects are created either establishing an outgoing connection
+with `<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial()>>` or by
+accepting in incoming connection with
+`<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept()>>`.
+
+TCP 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_tcp_send.3tcp#,nng_tcp_send()>>` or
+received with `<<nng_tcp_recv.3tcp#,nng_tcp_recv()>>`.
+
+When the connection is no longer needed, it should be freed with
+`<<nng_tcp_free.3tcp#,nng_tcp_free()>>`.
+
+TIP: It is possible to close the connection, without freeing it, by
+using `<<nng_tcp_close.3tcp#,nng_tcp_close()>>`.
+
+== SEE ALSO
+
+[.text-left]
+<<libnng.3#,libnng(3)>>,
+<<nng_tcp_close.3tcp#,nng_tcp_close(3tcp)>>,
+<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial(3tcp)>>,
+<<nng_tcp_free.3tcp#,nng_tcp_free(3tcp)>>,
+<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept(3tcp)>>,
+<<nng_tcp_peername.3tcp#,nng_tcp_peername(3tcp)>>,
+<<nng_tcp_recv.3tcp#,nng_tcp_recv(3tcp)>>,
+<<nng_tcp_send.3tcp#,nng_tcp_send(3tcp)>>,
+<<nng_tcp_sockname.3tcp#,nng_tcp_sockname(3tcp)>>,
+<<nng_tcp_set_keepalive.3tcp#,nng_tcp_set_keepalive(3tcp)>>,
+<<nng_tcp_set_nodelay.3tcp#,nng_tcp_set_nodelay(3tcp)>>,
+<<nng.7#,nng(7)>>
diff --git a/docs/man/nng_tcp_close.3tcp.adoc b/docs/man/nng_tcp_close.3tcp.adoc
new file mode 100644
index 00000000..6428501c
--- /dev/null
+++ b/docs/man/nng_tcp_close.3tcp.adoc
@@ -0,0 +1,60 @@
+= nng_tcp_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_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
new file mode 100644
index 00000000..99df685d
--- /dev/null
+++ b/docs/man/nng_tcp_dialer.5.adoc
@@ -0,0 +1,49 @@
+= nng_tcp_dialer(5)
+//
+// 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 - 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 a 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
new file mode 100644
index 00000000..4d06900e
--- /dev/null
+++ b/docs/man/nng_tcp_dialer_alloc.3tcp.adoc
@@ -0,0 +1,48 @@
+= 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_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.5#,nng_tcp_dialer(5)>>,
+<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_tcp_dialer_close.3tcp.adoc b/docs/man/nng_tcp_dialer_close.3tcp.adoc
new file mode 100644
index 00000000..94b720d5
--- /dev/null
+++ b/docs/man/nng_tcp_dialer_close.3tcp.adoc
@@ -0,0 +1,58 @@
+= 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 dial operations
+(see `<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial()>>`) 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(3tcp)>>`
+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
new file mode 100644
index 00000000..66893f93
--- /dev/null
+++ b/docs/man/nng_tcp_dialer_dial.3tcp.adoc
@@ -0,0 +1,63 @@
+= nng_tcp_dialer_dial(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_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 TCP connection was refused by the server.
+`NNG_ECONNRESET`:: The TCP 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
new file mode 100644
index 00000000..3116ad8e
--- /dev/null
+++ b/docs/man/nng_tcp_dialer_free.3tcp.adoc
@@ -0,0 +1,53 @@
+= 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 dial operations
+(see `<<nng_tcp_dialer_dial.3tcp#,nng_tcp_dialer_dial()>>`) 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_free.3tcp.adoc b/docs/man/nng_tcp_free.3tcp.adoc
new file mode 100644
index 00000000..3a9f5ff1
--- /dev/null
+++ b/docs/man/nng_tcp_free.3tcp.adoc
@@ -0,0 +1,58 @@
+= 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_listener.5.adoc b/docs/man/nng_tcp_listener.5.adoc
new file mode 100644
index 00000000..851ff2fa
--- /dev/null
+++ b/docs/man/nng_tcp_listener.5.adoc
@@ -0,0 +1,50 @@
+= nng_tcp_listener(5)
+//
+// 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 - 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>>` 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_listen.3tcp#,nng_tcp_listener_listen(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
new file mode 100644
index 00000000..9f0b4e6d
--- /dev/null
+++ b/docs/man/nng_tcp_listener_accept.3tcp.adoc
@@ -0,0 +1,67 @@
+= 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 listening.
+(See `<<nng_tcp_listener_listen.3tcp#,nng_tcp_listener_listen()>>`.)
+
+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 by using the
+`<<nng_tcp_peername.3tcp#,nng_tcp_peername()>>` function on the
+returned `<<nng_tcp.5#,nng_tcp>>`.
+
+== RETURN VALUES
+
+None.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECANCELED`:: The operation was aborted.
+`NNG_ECLOSED`:: The dialer 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
new file mode 100644
index 00000000..14276824
--- /dev/null
+++ b/docs/man/nng_tcp_listener_alloc.3tcp.adoc
@@ -0,0 +1,49 @@
+= 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_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_listen.3tcp#,nng_tcp_listener_listen(3tcp)>>,
+<<nng_tcp_listener.5#,nng_tcp_listener(5)>>,
+<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_tcp_listener_close.3tcp.adoc b/docs/man/nng_tcp_listener_close.3tcp.adoc
new file mode 100644
index 00000000..57b7088e
--- /dev/null
+++ b/docs/man/nng_tcp_listener_close.3tcp.adoc
@@ -0,0 +1,58 @@
+= nng_tcp_listener_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_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 acceppt operations
+(see `<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept()>>`) 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(3tcp)>>`
+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
new file mode 100644
index 00000000..cd37935c
--- /dev/null
+++ b/docs/man/nng_tcp_listener_free.3tcp.adoc
@@ -0,0 +1,52 @@
+= 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 accept operations
+(see `<<nng_tcp_listener_accept.3tcp#,nng_tcp_listener_accept()>>`) 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_listen.3tcp.adoc b/docs/man/nng_tcp_listener_listen.3tcp.adoc
new file mode 100644
index 00000000..5ff9ea80
--- /dev/null
+++ b/docs/man/nng_tcp_listener_listen.3tcp.adoc
@@ -0,0 +1,66 @@
+= nng_tcp_listener_listen(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_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, 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 _sa_ will be updated with the port chosen.
+
+== 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_sockaddr.5#,nng_sockaddr(5)>>,
+<<nng_tcp_listener.5#,nng_tcp_listener(5)>>
diff --git a/docs/man/nng_tcp_peername.3tcp.adoc b/docs/man/nng_tcp_peername.3tcp.adoc
new file mode 100644
index 00000000..c5f5ece6
--- /dev/null
+++ b/docs/man/nng_tcp_peername.3tcp.adoc
@@ -0,0 +1,45 @@
+= nng_tcp_peername(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_peername - get TCP peer socket address
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+int nng_tcp_peername(nng_tcp *conn, nng_sockaddr *sa);
+----
+
+== DESCRIPTION
+
+The `nng_tcp_peername()` is retrieves the TCP address of the remote
+peer on the connection _conn_, and stores it in _sa_.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection _conn_ is closed.
+
+== SEE ALSO
+
+[.text-left]
+<<nng_tcp_sockname.3tcp#,nng_tcp_sockname(3tcp)>>,
+<<nng_strerror.3#,nng_strerror(3)>>,
+<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_recv.3tcp.adoc b/docs/man/nng_tcp_recv.3tcp.adoc
new file mode 100644
index 00000000..5db9ea52
--- /dev/null
+++ b/docs/man/nng_tcp_recv.3tcp.adoc
@@ -0,0 +1,74 @@
+= nng_tcp_recv(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_recv - receive from TCP connection
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+void nng_tcp_recv(nng_tcp *conn, 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
+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()>>`.
+
+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_send.3tcp#,nng_tcp_send(3tcp)>>,
+<<nng_tcp.5#,nng_tcp(5)>>,
+<<nng_strerror.3#,nng_strerror(3)>>
diff --git a/docs/man/nng_tcp_send.3tcp.adoc b/docs/man/nng_tcp_send.3tcp.adoc
new file mode 100644
index 00000000..723781d5
--- /dev/null
+++ b/docs/man/nng_tcp_send.3tcp.adoc
@@ -0,0 +1,73 @@
+= 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_set_keepalive.3tcp.adoc b/docs/man/nng_tcp_set_keepalive.3tcp.adoc
new file mode 100644
index 00000000..8118861a
--- /dev/null
+++ b/docs/man/nng_tcp_set_keepalive.3tcp.adoc
@@ -0,0 +1,55 @@
+= nng_tcp_set_keepalive(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_set_keepalive - enable or disable TCP keepalives
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+int nng_tcp_set_keepalive(nng_tcp *conn, bool keepalive);
+----
+
+== DESCRIPTION
+
+The `nng_tcp_set_keepalive()` is used to enable or disable ((TCP keepalives))
+on the connection named by _conn_, depending on the value of _keepalive_.
+
+Different platforms have varying degress of support, with different thresholds
+for the interval between keep alive messages, and the duration required for
+a remote peer to be assumed to be offline.
+
+TIP: Keepalives can help keep a connection active, and prevent firewalls or
+other network equipment from discarding routing information as "`stale`",
+but enabling this means interruptions in connectivity will cause a
+connection to fail, which might otherwise be able to recover.
+Keepalives can also prevent a system from going to sleep properly.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection _conn_ is closed.
+
+== SEE ALSO
+
+[.text-left]
+<<nng_tcp_recv.3tcp#,nng_tcp_recv(3tcp)>>,
+<<nng_strerror.3#,nng_strerror(3)>>,
+<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_set_nodelay.3tcp.adoc b/docs/man/nng_tcp_set_nodelay.3tcp.adoc
new file mode 100644
index 00000000..207bd5ca
--- /dev/null
+++ b/docs/man/nng_tcp_set_nodelay.3tcp.adoc
@@ -0,0 +1,56 @@
+= nng_tcp_set_nodelay(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_set_nodelay - disable Nagle's algorithm
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+int nng_tcp_set_nodelay(nng_tcp *conn, bool nodelay);
+----
+
+== DESCRIPTION
+
+The `nng_tcp_set_nodelay()` is used to disable (or enable) the use of
+((Nagle's algorithm)) on the TCP connection _conn_.
+
+The default setting is platform dependent.
+
+By setting _nodelay_ to `true`, Nagle's algorithm is disabled.
+This is normally the preferred setting for latency sensitive protocols.
+
+Setting the value to `false` can cause messages to be deferred before being
+sent over the network, in order to allow additional data to accumulate.
+This is reduces overhead associated with each message by allowing overheads
+such as packet headers to amortized across more data, giving better network
+efficiency, but comes at a penalty to latency.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection _conn_ is closed.
+
+== SEE ALSO
+
+[.text-left]
+<<nng_tcp_send.3tcp#,nng_tcp_send(3tcp)>>,
+<<nng_strerror.3#,nng_strerror(3)>>,
+<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/docs/man/nng_tcp_sockname.3tcp.adoc b/docs/man/nng_tcp_sockname.3tcp.adoc
new file mode 100644
index 00000000..9d847079
--- /dev/null
+++ b/docs/man/nng_tcp_sockname.3tcp.adoc
@@ -0,0 +1,45 @@
+= nng_tcp_sockname(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_sockname - get TCP local socket address
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+int nng_tcp_sockname(nng_tcp *conn, nng_sockaddr *sa);
+----
+
+== DESCRIPTION
+
+The `nng_tcp_sockname()` is retrieves the local TCP address associated with
+the connection _conn_, and stores it in _sa_.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+[horizontal]
+`NNG_ECLOSED`:: The connection _conn_ is closed.
+
+== SEE ALSO
+
+[.text-left]
+<<nng_tcp_peername.3tcp#,nng_tcp_peername(3tcp)>>,
+<<nng_strerror.3#,nng_strerror(3)>>,
+<<nng_tcp.5#,nng_tcp(5)>>
diff --git a/include/nng/supplemental/tcp/tcp.h b/include/nng/supplemental/tcp/tcp.h
new file mode 100644
index 00000000..992bfd81
--- /dev/null
+++ b/include/nng/supplemental/tcp/tcp.h
@@ -0,0 +1,148 @@
+//
+// 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_conn 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_conn_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_sockname obtains an nng_sockaddr associated with our local
+// address.
+NNG_DECL int nng_tcp_sockname(nng_tcp *, nng_sockaddr *);
+
+// nng_tcp_peername obtains an nng_sockaddr associated with our peer.
+NNG_DECL int nng_tcp_peername(nng_tcp *, nng_sockaddr *);
+
+// nng_tcp_set_nodelay is used to disable Nagle's algorithm (true) or
+// enable it. For latency sensitive applications, disable it. For
+// throughput operations involving tiny messages, leave it enabled. We
+// usually recommend disabling it.
+NNG_DECL int nng_tcp_set_nodelay(nng_tcp *, bool);
+
+// nng_set_keepalive is used to enable the use of TCP keepalives.
+// At the moment there is no further tuning, because the tunables here
+// tend to be fairly platform specific.
+NNG_DECL int nng_tcp_set_keepalive(nng_tcp *, bool);
+
+// 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_set_source is used to set the source address that the
+// dialer should dial from. The port component of the socket address is
+// ignored, as a source port is always chosen at random. If this is not
+// called, then a system specific default source address is chosen.
+// (Usually the local interface IP address chosen based on the route to
+// the destination.)
+NNG_DECL int nng_tcp_dialer_set_source(nng_tcp_dialer *, const nng_sockaddr *);
+
+// 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_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.
+// On success, the sockaddr will be update with the actual address bound.
+// This is useful if the TCP port number 0 is specified, which permits
+// the implementation to choose a free random port. The caller can then
+// inspect the sockaddr to learn the actual bound port.
+NNG_DECL int nng_tcp_listener_listen(nng_tcp_listener *, 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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NNG_SUPPLEMENTAL_TCP_TCP_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dff34f9f..3d127993 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -182,6 +182,7 @@ add_subdirectory(transport/zerotier)
add_subdirectory(supplemental/base64)
add_subdirectory(supplemental/http)
add_subdirectory(supplemental/sha1)
+add_subdirectory(supplemental/tcp)
add_subdirectory(supplemental/tls)
add_subdirectory(supplemental/util)
add_subdirectory(supplemental/websocket)
diff --git a/src/supplemental/tcp/CMakeLists.txt b/src/supplemental/tcp/CMakeLists.txt
new file mode 100644
index 00000000..ef82b098
--- /dev/null
+++ b/src/supplemental/tcp/CMakeLists.txt
@@ -0,0 +1,15 @@
+#
+# Copyright 2018 Capitar IT Group BV <info@capitar.com>
+# Copyright 2018 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.
+#
+
+set(_SRCS supplemental/tcp/tcp.c
+ ${PROJECT_SOURCE_DIR}/include/nng/supplemental/tcp/tcp.h
+)
+
+set(NNG_SRCS ${NNG_SRCS} ${_SRCS} PARENT_SCOPE)
diff --git a/src/supplemental/tcp/tcp.c b/src/supplemental/tcp/tcp.c
new file mode 100644
index 00000000..4253e371
--- /dev/null
+++ b/src/supplemental/tcp/tcp.c
@@ -0,0 +1,153 @@
+//
+// 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.
+//
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <nng/nng.h>
+#include <nng/supplemental/tcp/tcp.h>
+
+#include "core/nng_impl.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.
+
+// 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)
+{
+ nni_tcp_conn_close((void *) tcp);
+}
+
+void
+nng_tcp_free(nng_tcp *tcp)
+{
+ nni_tcp_conn_fini((void *) tcp);
+}
+
+void
+nng_tcp_send(nng_tcp *tcp, nng_aio *aio)
+{
+ nni_tcp_conn_send((void *) tcp, aio);
+}
+
+void
+nng_tcp_recv(nng_tcp *tcp, nng_aio *aio)
+{
+ nni_tcp_conn_recv((void *) tcp, aio);
+}
+
+int
+nng_tcp_sockname(nng_tcp *tcp, nng_sockaddr *sa)
+{
+ return (nni_tcp_conn_sockname((void *) tcp, sa));
+}
+
+int
+nng_tcp_peername(nng_tcp *tcp, nng_sockaddr *sa)
+{
+ return (nni_tcp_conn_peername((void *) tcp, sa));
+}
+
+int
+nng_tcp_set_nodelay(nng_tcp *tcp, bool nodelay)
+{
+ return (nni_tcp_conn_set_nodelay((void *) tcp, nodelay));
+}
+
+int
+nng_tcp_set_keepalive(nng_tcp *tcp, bool ka)
+{
+ return (nni_tcp_conn_set_keepalive((void *) tcp, ka));
+}
+
+int
+nng_tcp_dialer_alloc(nng_tcp_dialer **dp)
+{
+ nni_tcp_dialer *d;
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+ if ((rv = nni_tcp_dialer_init(&d)) == 0) {
+ *dp = (void *) d;
+ }
+ return (rv);
+}
+
+void
+nng_tcp_dialer_close(nng_tcp_dialer *d)
+{
+ nni_tcp_dialer_close((void *) d);
+}
+
+void
+nng_tcp_dialer_free(nng_tcp_dialer *d)
+{
+ nni_tcp_dialer_fini((void *) d);
+}
+
+int
+nng_tcp_dialer_set_source(nng_tcp_dialer *d, const nng_sockaddr *sa)
+{
+ return (nni_tcp_dialer_set_src_addr((void *) d, sa));
+}
+
+void
+nng_tcp_dialer_dial(nng_tcp_dialer *d, const nng_sockaddr *sa, nng_aio *aio)
+{
+ return (nni_tcp_dialer_dial((void *) d, sa, aio));
+}
+
+int
+nng_tcp_listener_alloc(nng_tcp_listener **lp)
+{
+ nni_tcp_listener *l;
+ int rv;
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+ if ((rv = nni_tcp_listener_init(&l)) == 0) {
+ *lp = (void *) l;
+ }
+ return (rv);
+}
+
+void
+nng_tcp_listener_close(nng_tcp_listener *l)
+{
+ nni_tcp_listener_close((void *) l);
+}
+
+void
+nng_tcp_listener_free(nng_tcp_listener *l)
+{
+ nni_tcp_listener_fini((void *) l);
+}
+
+int
+nng_tcp_listener_listen(nng_tcp_listener *l, nng_sockaddr *sa)
+{
+ return (nni_tcp_listener_listen((void *) l, sa));
+}
+
+void
+nng_tcp_listener_accept(nng_tcp_listener *l, nng_aio *aio)
+{
+ return (nni_tcp_listener_accept((void *) l, aio));
+}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 89df9610..fdf0d98b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -167,6 +167,7 @@ add_nng_test(sock 5)
add_nng_test1(stats 5 NNG_ENABLE_STATS)
add_nng_test1(synch 5 NNG_STATIC_LIB)
add_nng_test2(tls 60 NNG_STATIC_LIB NNG_TRANSPORT_TLS)
+add_nng_test(tcpsupp 10)
add_nng_test1(tcp 180 NNG_TRANSPORT_TCP)
add_nng_test2(tcp6 60 NNG_STATIC_LIB NNG_TRANSPORT_TCP)
add_nng_test1(transport 5 NNG_STATIC_LIB)
diff --git a/tests/tcpsupp.c b/tests/tcpsupp.c
new file mode 100644
index 00000000..93c0ca9b
--- /dev/null
+++ b/tests/tcpsupp.c
@@ -0,0 +1,160 @@
+//
+// 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.
+//
+
+#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);
+ Reset({
+ nng_tcp_listener_close(l);
+ nng_tcp_dialer_close(d);
+ nng_tcp_listener_free(l);
+ nng_tcp_dialer_free(d);
+ });
+ Convey("Listener listens (wildcard)", {
+ nng_sockaddr sa;
+ uint32_t ip;
+
+ memcpy(&ip, loopback, 4);
+
+ sa.s_in.sa_family = NNG_AF_INET;
+ sa.s_in.sa_addr = ip;
+ sa.s_in.sa_port = 0;
+
+ So(nng_tcp_listener_listen(l, &sa) == 0);
+ So(sa.s_in.sa_port != 0);
+ So(sa.s_in.sa_addr == ip);
+
+ 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;
+
+ So(nng_aio_alloc(&daio, NULL, NULL) == 0);
+ So(nng_aio_alloc(&laio, NULL, NULL) == 0);
+ So(nng_aio_alloc(&maio, NULL, NULL) == 0);
+
+ Reset({
+ nng_aio_free(daio);
+ nng_aio_free(laio);
+ if (c1 != NULL) {
+ nng_tcp_close(c1);
+ nng_tcp_free(c1);
+ }
+ if (c2 != NULL) {
+ nng_tcp_close(c2);
+ nng_tcp_free(c2);
+ }
+ });
+
+ nng_tcp_dialer_dial(d, &sa, daio);
+ nng_tcp_listener_accept(l, laio);
+
+ nng_aio_wait(daio);
+ nng_aio_wait(laio);
+
+ So(nng_aio_result(daio) == 0);
+ So(nng_aio_result(laio) == 0);
+
+ c1 = nng_aio_get_output(daio, 0);
+ c2 = nng_aio_get_output(laio, 0);
+ So(c1 != NULL);
+ So(c2 != NULL);
+
+ Convey("They exchange messages", {
+ nng_aio * aio1;
+ nng_aio * aio2;
+ nng_iov iov;
+ nng_sockaddr sa2;
+ char buf1[5];
+ char buf2[5];
+
+ So(nng_aio_alloc(&aio1, NULL, NULL) ==
+ 0);
+ So(nng_aio_alloc(&aio2, NULL, NULL) ==
+ 0);
+
+ Reset({
+ nng_aio_free(aio1);
+ nng_aio_free(aio2);
+ });
+
+ So(nng_tcp_set_nodelay(c1, true) == 0);
+ So(nng_tcp_set_nodelay(c2, true) == 0);
+
+ So(nng_tcp_set_keepalive(c1, true) ==
+ 0);
+ // This relies on send completing for
+ // for just 5 bytes, and on recv doing
+ // the same. Technically this isn't
+ // guaranteed, but it would be weird
+ // to split such a small payload.
+ memcpy(buf1, "TEST", 5);
+ memset(buf2, 0, 5);
+ iov.iov_buf = buf1;
+ iov.iov_len = 5;
+
+ nng_aio_set_iov(aio1, 1, &iov);
+
+ 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_aio_wait(aio1);
+ nng_aio_wait(aio2);
+
+ So(nng_aio_result(aio1) == 0);
+ So(nng_aio_count(aio1) == 5);
+
+ So(nng_aio_result(aio2) == 0);
+ So(nng_aio_count(aio2) == 5);
+
+ So(memcmp(buf1, buf2, 5) == 0);
+
+ Convey("Socket name matches", {
+ So(nng_tcp_sockname(
+ c2, &sa2) == 0);
+ So(sa2.s_in.sa_family ==
+ NNG_AF_INET);
+ So(sa2.s_in.sa_addr == ip);
+ So(sa2.s_in.sa_port ==
+ sa.s_in.sa_port);
+ });
+
+ Convey("Peer name matches", {
+ So(nng_tcp_peername(
+ c1, &sa2) == 0);
+ So(sa2.s_in.sa_family ==
+ NNG_AF_INET);
+ So(sa2.s_in.sa_addr == ip);
+ So(sa2.s_in.sa_port ==
+ sa.s_in.sa_port);
+ });
+ });
+ });
+ });
+ });
+})