diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-06-29 18:05:56 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-06-29 18:05:56 -0700 |
| commit | 0cb73648b774f57135f56045a2fdb773fdf9c88b (patch) | |
| tree | aa9f9726ffcc5df9e7936daa0d0d3994378ad839 /src | |
| parent | fa6c49708c1e4bbb2bb0b93f1dbce6887cfb2193 (diff) | |
| download | nng-0cb73648b774f57135f56045a2fdb773fdf9c88b.tar.gz nng-0cb73648b774f57135f56045a2fdb773fdf9c88b.tar.bz2 nng-0cb73648b774f57135f56045a2fdb773fdf9c88b.zip | |
Use common POSIX socket handling for IPC.
Diffstat (limited to 'src')
| -rw-r--r-- | src/platform/posix/posix_ipc.c | 336 | ||||
| -rw-r--r-- | src/platform/posix/posix_net.c | 4 | ||||
| -rw-r--r-- | src/platform/posix/posix_socket.c | 4 |
3 files changed, 47 insertions, 297 deletions
diff --git a/src/platform/posix/posix_ipc.c b/src/platform/posix/posix_ipc.c index 44307ca5..04d83556 100644 --- a/src/platform/posix/posix_ipc.c +++ b/src/platform/posix/posix_ipc.c @@ -11,6 +11,7 @@ #ifdef PLATFORM_POSIX_IPC #include "platform/posix/posix_aio.h" +#include "platform/posix/posix_socket.h" #include <errno.h> #include <stdlib.h> @@ -30,368 +31,113 @@ #undef sun #endif -struct nni_plat_ipcsock { - int fd; - int devnull; // for shutting down accept() - char * unlink; // path to unlink at fini - nni_posix_pipedesc * pd; -}; - -#ifdef SOCK_CLOEXEC -#define NNI_IPC_SOCKTYPE (SOCK_STREAM | SOCK_CLOEXEC) -#else -#define NNI_IPC_SOCKTYPE SOCK_STREAM -#endif +// We alias nni_posix_sock to nni_plat_ipcsock. static int -nni_plat_ipc_path_to_sockaddr(struct sockaddr_un *sun, const char *path) +nni_plat_ipc_path_resolve(nni_sockaddr *addr, const char *path) { - memset(sun, 0, sizeof (*sun)); - sun->sun_family = PF_UNIX; + nng_sockaddr_path *spath; + size_t len; - // Technically on some platforms we could support path names larger - // than the path, and on others we could skip null termination. We - // take a conservative approach, which is that the path must fit in - // the supplied character array, and *must* be NULL terminated. + memset(addr, 0, sizeof (*addr)); + spath = &addr->s_un.s_path; // TODO: abstract sockets, including autobind sockets. - if (strlen(path) >= sizeof (sun->sun_path)) { + len = strlen(path); + if ((len >= sizeof (spath->sa_path)) || (len < 1)) { return (NNG_EADDRINVAL); } - if (strlen(path) == 0) { - return (-1); - } - snprintf(sun->sun_path, sizeof (sun->sun_path), "%s", path); - return (sizeof (*sun)); -} - - -void -nni_plat_ipc_aio_send(nni_plat_ipcsock *isp, nni_aio *aio) -{ - nni_posix_pipedesc_write(isp->pd, aio); -} - - -void -nni_plat_ipc_aio_recv(nni_plat_ipcsock *isp, nni_aio *aio) -{ - nni_posix_pipedesc_read(isp->pd, aio); + (void) snprintf(spath->sa_path, sizeof (spath->sa_path), "%s", path); + spath->sa_family = NNG_AF_IPC; + return (0); } int nni_plat_ipc_send(nni_plat_ipcsock *s, nni_iov *iovs, int cnt) { - struct iovec iov[4]; // We never have more than 3 at present - int i; - int offset; - int resid = 0; - int rv; - - if (cnt > 4) { - return (NNG_EINVAL); - } - - for (i = 0; i < cnt; i++) { - iov[i].iov_base = iovs[i].iov_buf; - iov[i].iov_len = iovs[i].iov_len; - resid += iov[i].iov_len; - } - - i = 0; - while (resid) { - rv = writev(s->fd, &iov[i], cnt); - if (rv < 0) { - if (rv == EINTR) { - continue; - } - return (nni_plat_errno(errno)); - } - if (rv > resid) { - nni_panic("writev says it wrote too much!"); - } - resid -= rv; - while (rv) { - if (iov[i].iov_len <= rv) { - rv -= iov[i].iov_len; - i++; - cnt--; - } else { - iov[i].iov_len -= rv; - iov[i].iov_base += rv; - rv = 0; - } - } - } - - return (0); + return (nni_posix_sock_send_sync((void *) s, iovs, cnt)); } int nni_plat_ipc_recv(nni_plat_ipcsock *s, nni_iov *iovs, int cnt) { - struct iovec iov[4]; // We never have more than 3 at present - int i; - int offset; - int resid = 0; - int rv; - - if (cnt > 4) { - return (NNG_EINVAL); - } + return (nni_posix_sock_recv_sync((void *) s, iovs, cnt)); +} - for (i = 0; i < cnt; i++) { - iov[i].iov_base = iovs[i].iov_buf; - iov[i].iov_len = iovs[i].iov_len; - resid += iov[i].iov_len; - } - i = 0; - while (resid) { - rv = readv(s->fd, &iov[i], cnt); - if (rv < 0) { - if (errno == EINTR) { - continue; - } - return (nni_plat_errno(errno)); - } - if (rv == 0) { - return (NNG_ECLOSED); - } - if (rv > resid) { - nni_panic("readv says it read too much!"); - } - - resid -= rv; - while (rv) { - if (iov[i].iov_len <= rv) { - rv -= iov[i].iov_len; - i++; - cnt--; - } else { - iov[i].iov_len -= rv; - iov[i].iov_base += rv; - rv = 0; - } - } - } - return (0); +void +nni_plat_ipc_aio_send(nni_plat_ipcsock *s, nni_aio *aio) +{ + nni_posix_sock_aio_send((void *) s, aio); } -static void -nni_plat_ipc_setopts(int fd) +void +nni_plat_ipc_aio_recv(nni_plat_ipcsock *s, nni_aio *aio) { - int one; - - // Try to ensure that both CLOEXEC is set, and that we don't - // generate SIGPIPE. (Note that SIGPIPE suppression in this way - // only works on BSD systems. Linux wants us to use sendmsg().) - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); -#if defined(F_SETNOSIGPIPE) - (void) fcntl(fd, F_SETNOSIGPIPE, 1); -#elif defined(SO_NOSIGPIPE) - one = 1; - (void) setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof (one)); -#endif + nni_posix_sock_aio_recv((void *) s, aio); } int -nni_plat_ipc_init(nni_plat_ipcsock **ispp) +nni_plat_ipc_init(nni_plat_ipcsock **sp) { - nni_plat_ipcsock *isp; + nni_posix_sock *s; + int rv; - if ((isp = NNI_ALLOC_STRUCT(isp)) == NULL) { - return (NNG_ENOMEM); + if ((rv = nni_posix_sock_init(&s)) == 0) { + *sp = (void *) s; } - isp->fd = -1; - *ispp = isp; - return (0); + return (rv); } void -nni_plat_ipc_fini(nni_plat_ipcsock *isp) +nni_plat_ipc_fini(nni_plat_ipcsock *s) { - if (isp->fd != -1) { - (void) close(isp->fd); - isp->fd = -1; - } - if (isp->unlink != NULL) { - (void) unlink(isp->unlink); - nni_free(isp->unlink, strlen(isp->unlink) + 1); - } - - if (isp->pd != NULL) { - nni_posix_pipedesc_fini(isp->pd); - } - - NNI_FREE_STRUCT(isp); + nni_posix_sock_fini((void *) s); } void -nni_plat_ipc_shutdown(nni_plat_ipcsock *isp) +nni_plat_ipc_shutdown(nni_plat_ipcsock *s) { - if (isp->fd != -1) { - (void) shutdown(isp->fd, SHUT_RDWR); - // This causes the equivalent of a close. Hopefully waking - // up anything that didn't get the hint with the shutdown. - // (macOS does not see the shtudown). - (void) dup2(nni_plat_devnull, isp->fd); - } - if (isp->pd != NULL) { - nni_posix_pipedesc_close(isp->pd); - } + nni_posix_sock_shutdown((void *) s); } -// nni_plat_ipc_listen creates a file descriptor bound to the given address. -// This basically does the equivalent of socket, bind, and listen. We have -// chosen a default value for the listen backlog of 128, which should be -// plenty. (If it isn't, then the accept thread can't get enough resources -// to keep up, and your clients are going to experience bad things. Normally -// the actual backlog should hover near 0 anyway.) int nni_plat_ipc_listen(nni_plat_ipcsock *s, const char *path) { - int fd, checkfd; - struct sockaddr_un sun; int rv; + nni_sockaddr addr; - if (nni_plat_ipc_path_to_sockaddr(&sun, path) < 0) { - return (NNG_EADDRINVAL); - } - - if ((fd = socket(AF_UNIX, NNI_IPC_SOCKTYPE, 0)) < 0) { - return (nni_plat_errno(errno)); - } - - // We are going to check to see if there was a name already there. - // If there was, and nothing is listening (ECONNREFUSED), then we - // will just try to cleanup the old socket. Note that this is not - // perfect in all scenarios, so use this with caution. - if ((checkfd = socket(AF_UNIX, NNI_IPC_SOCKTYPE, 0)) < 0) { - (void) close(fd); - return (nni_plat_errno(errno)); - } - - // Nonblocking because we don't want to wait for any remote server. - (void) fcntl(checkfd, F_SETFL, O_NONBLOCK); - if (connect(checkfd, (struct sockaddr *) &sun, sizeof (sun)) < 0) { - if (errno == ECONNREFUSED) { - (void) unlink(path); - } - } - (void) close(checkfd); - - nni_plat_ipc_setopts(fd); - - if ((s->unlink = nni_alloc(strlen(path) + 1)) == NULL) { - return (NNG_ENOMEM); - } - strcpy(s->unlink, path); - if (bind(fd, (struct sockaddr *) &sun, sizeof (sun)) < 0) { - rv = nni_plat_errno(errno); - nni_free(s->unlink, strlen(path) + 1); - s->unlink = NULL; - (void) close(fd); - return (rv); - } - - // Listen -- 128 depth is probably sufficient. If it isn't, other - // bad things are going to happen. - if (listen(fd, 128) < 0) { - rv = nni_plat_errno(errno); - (void) close(fd); + if ((rv = nni_plat_ipc_path_resolve(&addr, path)) != 0) { return (rv); } - s->fd = fd; - return (0); + return (nni_posix_sock_listen((void *) s, &addr)); } int -nni_plat_ipc_connect(nni_plat_ipcsock *isp, const char *path) +nni_plat_ipc_connect(nni_plat_ipcsock *s, const char *path) { - int fd; - int len; - struct sockaddr_un sun; int rv; + nni_sockaddr addr; - if (nni_plat_ipc_path_to_sockaddr(&sun, path) < 0) { - return (NNG_EADDRINVAL); - } - - if ((fd = socket(AF_UNIX, NNI_IPC_SOCKTYPE, 0)) < 0) { - return (nni_plat_errno(errno)); - } - - nni_plat_ipc_setopts(fd); - - if (connect(fd, (struct sockaddr *) &sun, sizeof (sun)) != 0) { - rv = nni_plat_errno(errno); - (void) close(fd); - if (rv == NNG_ENOENT) { - // In this case we want to treat this the same as - // ECONNREFUSED, since they mean the same to us. - rv = NNG_ECONNREFUSED; - } - return (rv); - } - - if ((rv = nni_posix_pipedesc_init(&isp->pd, fd)) != 0) { - (void) close(fd); + if ((rv = nni_plat_ipc_path_resolve(&addr, path)) != 0) { return (rv); } - - isp->fd = fd; - return (0); + return (nni_posix_sock_connect_sync((void *) s, &addr, NULL)); } int -nni_plat_ipc_accept(nni_plat_ipcsock *isp, nni_plat_ipcsock *server) +nni_plat_ipc_accept(nni_plat_ipcsock *s, nni_plat_ipcsock *server) { - int fd; - int rv; - - for (;;) { -#ifdef NNG_USE_ACCEPT4 - fd = accept4(server->fd, NULL, NULL, SOCK_CLOEXEC); - if ((fd < 0) && ((errno == ENOSYS) || (errno == ENOTSUP))) { - fd = accept(server->fd, NULL, NULL); - } -#else - fd = accept(server->fd, NULL, NULL); -#endif - - if (fd < 0) { - if ((errno == EINTR) || (errno == ECONNABORTED)) { - // These are not fatal errors, keep trying - continue; - } - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - continue; - } - return (nni_plat_errno(errno)); - } else { - break; - } - } - - nni_plat_ipc_setopts(fd); - - if ((rv = nni_posix_pipedesc_init(&isp->pd, fd)) != 0) { - (void) close(fd); - return (rv); - } - - isp->fd = fd; - return (0); + return (nni_posix_sock_accept_sync((void *) s, (void *) server)); } diff --git a/src/platform/posix/posix_net.c b/src/platform/posix/posix_net.c index 161ffc7c..4ba67f9c 100644 --- a/src/platform/posix/posix_net.c +++ b/src/platform/posix/posix_net.c @@ -85,13 +85,13 @@ nni_plat_tcp_aio_recv(nni_plat_tcpsock *s, nni_aio *aio) int -nni_plat_tcp_init(nni_plat_tcpsock **tspp) +nni_plat_tcp_init(nni_plat_tcpsock **sp) { nni_posix_sock *s; int rv; if ((rv = nni_posix_sock_init(&s)) == 0) { - *tspp = (void *) s; + *sp = (void *) s; } return (rv); } diff --git a/src/platform/posix/posix_socket.c b/src/platform/posix/posix_socket.c index 843bbd1e..6aa17978 100644 --- a/src/platform/posix/posix_socket.c +++ b/src/platform/posix/posix_socket.c @@ -219,6 +219,10 @@ nni_posix_sock_fini(nni_posix_sock *s) if (s->pd != NULL) { nni_posix_pipedesc_fini(s->pd); } + if (s->unlink != NULL) { + (void) unlink(s->unlink); + nni_free(s->unlink, strlen(s->unlink) + 1); + } NNI_FREE_STRUCT(s); } |
