summaryrefslogtreecommitdiff
path: root/src/compat
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-04-16 11:40:28 -0700
committerGarrett D'Amore <garrett@damore.org>2018-04-16 20:56:32 -0700
commit45f3f141850a0ac07c31906748752571652683df (patch)
tree0e14b8e5a72972e370f60ea5fd230a790195cd28 /src/compat
parente3b8f31b044e4fe7d47439467fc1622266b5335c (diff)
downloadnng-45f3f141850a0ac07c31906748752571652683df.tar.gz
nng-45f3f141850a0ac07c31906748752571652683df.tar.bz2
nng-45f3f141850a0ac07c31906748752571652683df.zip
fixes #344 nn_poll() legacy API missing
This includes the test from legacy libnanomsg and a man page. We have refactored the message queue notification system so that it uses nni_pollable, leading we hope to a more consistent system, and reducing the code size and complexity. We also fixed the size of the NN_RCVFD and NN_SNDFD so that they are a SOCKET on Windows systems, rather than an integer. This addresses 64-bit compilation problems.
Diffstat (limited to 'src/compat')
-rw-r--r--src/compat/nanomsg/nn.c152
1 files changed, 150 insertions, 2 deletions
diff --git a/src/compat/nanomsg/nn.c b/src/compat/nanomsg/nn.c
index cbb88a27..40671cfa 100644
--- a/src/compat/nanomsg/nn.c
+++ b/src/compat/nanomsg/nn.c
@@ -664,6 +664,39 @@ nn_getdomain(nng_socket s, void *valp, size_t *szp)
return (0);
}
+#ifndef NNG_PLATFORM_WINDOWS
+#define SOCKET int
+#endif
+
+static int
+nn_getfd(nng_socket s, void *valp, size_t *szp, const char *opt)
+{
+ int ifd;
+ int rv;
+ SOCKET sfd;
+
+ if ((rv = nng_getopt_int(s, opt, &ifd)) != 0) {
+ nn_seterror(rv);
+ return (-1);
+ }
+ sfd = (SOCKET) ifd;
+ memcpy(valp, &sfd, *szp < sizeof(sfd) ? *szp : sizeof(sfd));
+ *szp = sizeof(sfd);
+ return (0);
+}
+
+static int
+nn_getrecvfd(nng_socket s, void *valp, size_t *szp)
+{
+ return (nn_getfd(s, valp, szp, NNG_OPT_RECVFD));
+}
+
+static int
+nn_getsendfd(nng_socket s, void *valp, size_t *szp)
+{
+ return (nn_getfd(s, valp, szp, NNG_OPT_SENDFD));
+}
+
static int
nn_getzero(nng_socket s, void *valp, size_t *szp)
{
@@ -727,10 +760,16 @@ static const struct {
.opt = NNG_OPT_RECONNMAXT,
},
{
- .nnlevel = NN_SOL_SOCKET, .nnopt = NN_SNDFD, .opt = NNG_OPT_SENDFD,
+ .nnlevel = NN_SOL_SOCKET,
+ .nnopt = NN_SNDFD,
+ .opt = NNG_OPT_SENDFD,
+ .get = nn_getsendfd,
},
{
- .nnlevel = NN_SOL_SOCKET, .nnopt = NN_RCVFD, .opt = NNG_OPT_RECVFD,
+ .nnlevel = NN_SOL_SOCKET,
+ .nnopt = NN_RCVFD,
+ .opt = NNG_OPT_RECVFD,
+ .get = nn_getrecvfd,
},
{
.nnlevel = NN_SOL_SOCKET,
@@ -888,6 +927,115 @@ nn_device(int s1, int s2)
return (-1);
}
+// Windows stuff.
+#ifdef NNG_PLATFORM_WINDOWS
+#define poll WSAPoll
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <mswsock.h>
+#elif defined NNG_PLATFORM_POSIX
+#include <poll.h>
+#endif
+
+int
+nn_poll(struct nn_pollfd *fds, int nfds, int timeout)
+{
+// This function is rather unfortunate. poll() is available
+// on POSIX, and on Windows as WSAPoll. On other systems it might
+// not exist at all. We could also benefit from using a notification
+// that didn't have to access file descriptors... sort of access to
+// the pollable element on the socket. We don't have that, so we
+// just use poll. This function is definitely suboptimal compared to
+// using callbacks.
+#if defined(NNG_PLATFORM_WINDOWS) || defined(NNG_PLATFORM_POSIX)
+ struct pollfd *pfd;
+ int npfd;
+ int rv;
+
+ if ((pfd = NNI_ALLOC_STRUCTS(pfd, nfds * 2)) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ // First prepare the master polling structure.
+ npfd = 0;
+ for (int i = 0; i < nfds; i++) {
+ int fd;
+ if (fds[i].events & NN_POLLIN) {
+ if ((rv = nng_getopt_int((nng_socket) fds[i].fd,
+ NNG_OPT_RECVFD, &fd)) != 0) {
+ nn_seterror(rv);
+ NNI_FREE_STRUCTS(pfd, nfds * 2);
+ return (-1);
+ }
+#ifdef NNG_PLATFORM_WINDOWS
+ pfd[npfd].fd = (SOCKET) fd;
+#else
+ pfd[npfd].fd = fd;
+#endif
+ pfd[npfd].events = POLLIN;
+ npfd++;
+ }
+ if (fds[i].events & NN_POLLOUT) {
+ if ((rv = nng_getopt_int((nng_socket) fds[i].fd,
+ NNG_OPT_SENDFD, &fd)) != 0) {
+ nn_seterror(rv);
+ NNI_FREE_STRUCTS(pfd, nfds * 2);
+ return (-1);
+ }
+#ifdef NNG_PLATFORM_WINDOWS
+ pfd[npfd].fd = (SOCKET) fd;
+#else
+ pfd[npfd].fd = fd;
+#endif
+ pfd[npfd].events = POLLIN;
+ npfd++;
+ }
+ }
+
+ rv = poll(pfd, npfd, timeout);
+ if (rv < 0) {
+ int e = errno;
+ NNI_FREE_STRUCTS(pfd, nfds * 2);
+ errno = e;
+ return (-1);
+ }
+
+ // Now update the nn_poll from the system poll.
+ npfd = 0;
+ rv = 0;
+ for (int i = 0; i < nfds; i++) {
+ fds[i].revents = 0;
+ if (fds[i].events & NN_POLLIN) {
+ if (pfd[npfd].revents & POLLIN) {
+ fds[i].revents |= NN_POLLIN;
+ }
+ npfd++;
+ }
+ if (fds[i].events & NN_POLLOUT) {
+ if (pfd[npfd].revents & POLLIN) {
+ fds[i].revents |= NN_POLLOUT;
+ }
+ npfd++;
+ }
+ if (fds[i].revents) {
+ rv++;
+ }
+ }
+ NNI_FREE_STRUCTS(pfd, nfds * 2);
+ return (rv);
+
+#else // NNG_PLATFORM_WINDOWS or NNG_PLATFORM_POSIX
+ NNI_ARG_UNUSED(pfds);
+ NNI_ARG_UNUSED(npfd);
+ NNI_ARG_UNUSED(timeout);
+ errno = ENOTSUP;
+ return (-1);
+#endif
+}
+
// nn_term is suitable only for shutting down the entire library,
// and is not thread-safe with other functions.
void