aboutsummaryrefslogtreecommitdiff
path: root/src/platform/posix
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/posix')
-rw-r--r--src/platform/posix/posix_debug.c3
-rw-r--r--src/platform/posix/posix_ipclisten.c61
-rw-r--r--src/platform/posix/posix_tcplisten.c66
3 files changed, 130 insertions, 0 deletions
diff --git a/src/platform/posix/posix_debug.c b/src/platform/posix/posix_debug.c
index 912000cc..3c0a6604 100644
--- a/src/platform/posix/posix_debug.c
+++ b/src/platform/posix/posix_debug.c
@@ -90,6 +90,9 @@ static struct {
{ ENFILE, NNG_ENOFILES },
{ EMFILE, NNG_ENOFILES },
{ EEXIST, NNG_EEXIST },
+#ifdef ENOTSOCK
+ { ENOTSOCK, NNG_EINVAL },
+#endif
// must be last
{ 0, 0 },
// clang-format on
diff --git a/src/platform/posix/posix_ipclisten.c b/src/platform/posix/posix_ipclisten.c
index aa6ffda8..d13ac063 100644
--- a/src/platform/posix/posix_ipclisten.c
+++ b/src/platform/posix/posix_ipclisten.c
@@ -252,6 +252,60 @@ ipc_listener_set_perms(void *arg, const void *buf, size_t sz, nni_type t)
return (0);
}
+static int
+ipc_listener_set_listen_fd(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ ipc_listener *l = arg;
+ int fd;
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(ss);
+ int rv;
+
+ if ((rv = nni_copyin_int(&fd, buf, sz, 0, NNI_MAXINT, t)) != 0) {
+ return (rv);
+ }
+
+ if (getsockname(fd, (void *) &ss, &len) != 0) {
+ return (nni_plat_errno(errno));
+ }
+
+ if (((nni_posix_sockaddr2nn(&l->sa, &ss, len)) != 0) ||
+ (ss.ss_family != AF_UNIX)) {
+ return (NNG_EADDRINVAL);
+ }
+
+ nni_mtx_lock(&l->mtx);
+ if (l->started) {
+ nni_mtx_unlock(&l->mtx);
+ return (NNG_EBUSY);
+ }
+ if (l->closed) {
+ nni_mtx_unlock(&l->mtx);
+ return (NNG_ECLOSED);
+ }
+ nni_posix_pfd_init(&l->pfd, fd, ipc_listener_cb, l);
+ l->started = true;
+ nni_mtx_unlock(&l->mtx);
+ return (0);
+}
+
+#ifdef NNG_TEST_LIB
+// this is readable only for test code -- user code should never rely on this
+static int
+ipc_listener_get_listen_fd(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ int rv;
+ ipc_listener *l = arg;
+
+ nni_mtx_lock(&l->mtx);
+ NNI_ASSERT(l->started);
+ NNI_ASSERT(!l->closed);
+ rv = nni_copyout_int(nni_posix_pfd_fd(&l->pfd), buf, szp, t);
+ nni_mtx_unlock(&l->mtx);
+ return (rv);
+}
+#endif
+
static const nni_option ipc_listener_options[] = {
{
.o_name = NNG_OPT_LOCADDR,
@@ -262,6 +316,13 @@ static const nni_option ipc_listener_options[] = {
.o_set = ipc_listener_set_perms,
},
{
+ .o_name = NNG_OPT_LISTEN_FD,
+ .o_set = ipc_listener_set_listen_fd,
+#ifdef NNG_TEST_LIB
+ .o_get = ipc_listener_get_listen_fd,
+#endif
+ },
+ {
.o_name = NULL,
},
};
diff --git a/src/platform/posix/posix_tcplisten.c b/src/platform/posix/posix_tcplisten.c
index 6e7f4d14..29b5ea65 100644
--- a/src/platform/posix/posix_tcplisten.c
+++ b/src/platform/posix/posix_tcplisten.c
@@ -10,6 +10,7 @@
//
#include "core/nng_impl.h"
+#include "nng/nng.h"
#include <arpa/inet.h>
#include <errno.h>
@@ -402,6 +403,64 @@ tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t)
return (nni_copyout_int(port, buf, szp, t));
}
+static int
+tcp_listener_set_listen_fd(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ tcp_listener *l = arg;
+ int fd;
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(ss);
+ int rv;
+
+ if ((rv = nni_copyin_int(&fd, buf, sz, 0, NNI_MAXINT, t)) != 0) {
+ return (rv);
+ }
+
+ if (getsockname(fd, (void *) &ss, &len) != 0) {
+ return (nni_plat_errno(errno));
+ }
+
+ if (((nni_posix_sockaddr2nn(&l->sa, &ss, len)) != 0) ||
+#ifdef NNG_ENABLE_IPV6
+ ((ss.ss_family != AF_INET) && (ss.ss_family != AF_INET6))
+#else
+ (ss.ss_family != AF_INET)
+#endif
+ ) {
+ return (NNG_EADDRINVAL);
+ }
+
+ nni_mtx_lock(&l->mtx);
+ if (l->started) {
+ nni_mtx_unlock(&l->mtx);
+ return (NNG_EBUSY);
+ }
+ if (l->closed) {
+ nni_mtx_unlock(&l->mtx);
+ return (NNG_ECLOSED);
+ }
+ nni_posix_pfd_init(&l->pfd, fd, tcp_listener_cb, l);
+ l->started = true;
+ nni_mtx_unlock(&l->mtx);
+ return (0);
+}
+
+#ifdef NNG_TEST_LIB
+// this is readable only for test code -- user code should never rely on this
+static int
+tcp_listener_get_listen_fd(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ int rv;
+ tcp_listener *l = arg;
+ nni_mtx_lock(&l->mtx);
+ NNI_ASSERT(l->started);
+ NNI_ASSERT(!l->closed);
+ rv = nni_copyout_int(nni_posix_pfd_fd(&l->pfd), buf, szp, t);
+ nni_mtx_unlock(&l->mtx);
+ return (rv);
+}
+#endif
+
static const nni_option tcp_listener_options[] = {
{
.o_name = NNG_OPT_LOCADDR,
@@ -422,6 +481,13 @@ static const nni_option tcp_listener_options[] = {
.o_get = tcp_listener_get_port,
},
{
+ .o_name = NNG_OPT_LISTEN_FD,
+ .o_set = tcp_listener_set_listen_fd,
+#ifdef NNG_TEST_LIB
+ .o_get = tcp_listener_get_listen_fd,
+#endif
+ },
+ {
.o_name = NULL,
},
};