diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-04-16 11:40:28 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-04-16 20:56:32 -0700 |
| commit | 45f3f141850a0ac07c31906748752571652683df (patch) | |
| tree | 0e14b8e5a72972e370f60ea5fd230a790195cd28 /tests | |
| parent | e3b8f31b044e4fe7d47439467fc1622266b5335c (diff) | |
| download | nng-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 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/compat_poll.c | 201 | ||||
| -rw-r--r-- | tests/compat_testutil.h | 1 |
3 files changed, 203 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d6283dbc..08806679 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -186,6 +186,7 @@ add_nng_compat_test(compat_reqrep 5) add_nng_compat_test(compat_survey 5) add_nng_compat_test(compat_reqttl 5) add_nng_compat_test(compat_shutdown 5) +add_nng_compat_test(compat_poll 5) # These are special tests for compat mode, not inherited from the # legacy libnanomsg suite. diff --git a/tests/compat_poll.c b/tests/compat_poll.c new file mode 100644 index 00000000..1101eb0a --- /dev/null +++ b/tests/compat_poll.c @@ -0,0 +1,201 @@ +/* + Copyright (c) 2013 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + + +#if defined _WIN32 +#define poll WSAPoll +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <winsock2.h> +#include <mswsock.h> +#else +#include <sys/select.h> +#endif +#include "compat_testutil.h" +#include <nanomsg/nn.h> + +/* Test of polling via NN_SNDFD/NN_RCVFD mechanism. */ + +#define SOCKET_ADDRESS "inproc://a" + +int sc; + +void +routine1(NN_UNUSED void *arg) +{ + nn_sleep(10); + test_send(sc, "ABC"); +} + +void +routine2(NN_UNUSED void *arg) +{ + nn_sleep(10); + nn_term(); +} + +#define NN_IN 1 +#define NN_OUT 2 + +int +getevents(int s, int events, int timeout) +{ + int rc; + fd_set pollset; +#if defined _WIN32 + SOCKET rcvfd; + SOCKET sndfd; +#else + int rcvfd; + int sndfd; + int maxfd; +#endif + size_t fdsz; + struct timeval tv; + int revents; + +#if !defined _WIN32 + maxfd = 0; +#endif + FD_ZERO(&pollset); + + if (events & NN_IN) { + fdsz = sizeof(rcvfd); + rc = nn_getsockopt( + s, NN_SOL_SOCKET, NN_RCVFD, (char *) &rcvfd, &fdsz); + errno_assert(rc == 0); + nn_assert(fdsz == sizeof(rcvfd)); + FD_SET(rcvfd, &pollset); +#if !defined _WIN32 + if (rcvfd + 1 > maxfd) + maxfd = rcvfd + 1; +#endif + } + + if (events & NN_OUT) { + fdsz = sizeof(sndfd); + rc = nn_getsockopt( + s, NN_SOL_SOCKET, NN_SNDFD, (char *) &sndfd, &fdsz); + errno_assert(rc == 0); + nn_assert(fdsz == sizeof(sndfd)); + FD_SET(sndfd, &pollset); +#if !defined _WIN32 + if (sndfd + 1 > maxfd) + maxfd = sndfd + 1; +#endif + } + + if (timeout >= 0) { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + } +#if defined _WIN32 + rc = select(0, &pollset, NULL, NULL, timeout < 0 ? NULL : &tv); + wsa_assert(rc != SOCKET_ERROR); +#else + rc = select(maxfd, &pollset, NULL, NULL, timeout < 0 ? NULL : &tv); + errno_assert(rc >= 0); +#endif + revents = 0; + if ((events & NN_IN) && FD_ISSET(rcvfd, &pollset)) + revents |= NN_IN; + if ((events & NN_OUT) && FD_ISSET(sndfd, &pollset)) + revents |= NN_OUT; + return revents; +} + +int +main() +{ + int rc; + int sb; + char buf[3]; + struct nn_thread thread; + struct nn_pollfd pfd[2]; + + /* Test nn_poll() function. */ + sb = test_socket(AF_SP, NN_PAIR); + test_bind(sb, SOCKET_ADDRESS); + sc = test_socket(AF_SP, NN_PAIR); + test_connect(sc, SOCKET_ADDRESS); + nn_sleep(200); + test_send(sc, "ABC"); + nn_sleep(100); + pfd[0].fd = sb; + pfd[0].events = NN_POLLIN | NN_POLLOUT; + pfd[1].fd = sc; + pfd[1].events = NN_POLLIN | NN_POLLOUT; + rc = nn_poll(pfd, 2, -1); + errno_assert(rc >= 0); + nn_assert(rc == 2); + nn_assert(pfd[0].revents == (NN_POLLIN | NN_POLLOUT)); + nn_assert(pfd[1].revents == NN_POLLOUT); + test_close(sc); + test_close(sb); + + /* Create a simple topology. */ + sb = test_socket(AF_SP, NN_PAIR); + test_bind(sb, SOCKET_ADDRESS); + sc = test_socket(AF_SP, NN_PAIR); + test_connect(sc, SOCKET_ADDRESS); + + /* Check the initial state of the socket. */ + rc = getevents(sb, NN_IN | NN_OUT, 1000); + nn_assert(rc == NN_OUT); + + /* Poll for IN when there's no message available. The call should + time out. */ + rc = getevents(sb, NN_IN, 10); + nn_assert(rc == 0); + + /* Send a message and start polling. This time IN event should be + signaled. */ + test_send(sc, "ABC"); + rc = getevents(sb, NN_IN, 1000); + nn_assert(rc == NN_IN); + + /* Receive the message and make sure that IN is no longer signaled. */ + test_recv(sb, "ABC"); + rc = getevents(sb, NN_IN, 10); + nn_assert(rc == 0); + + /* Check signalling from a different thread. */ + nn_thread_init(&thread, routine1, NULL); + rc = getevents(sb, NN_IN, 1000); + nn_assert(rc == NN_IN); + test_recv(sb, "ABC"); + nn_thread_term(&thread); + + /* Check terminating the library from a different thread. */ + nn_thread_init(&thread, routine2, NULL); + rc = nn_recv(sb, buf, sizeof(buf), 0); + nn_assert(rc < 0 && nn_errno() == EBADF); + nn_thread_term(&thread); + + /* Clean up. */ + test_close(sc); + test_close(sb); + + return 0; +} diff --git a/tests/compat_testutil.h b/tests/compat_testutil.h index 745f5621..ce5968a2 100644 --- a/tests/compat_testutil.h +++ b/tests/compat_testutil.h @@ -40,6 +40,7 @@ #define nn_err_abort abort #define nn_assert assert #define errno_assert assert +#define wsa_assert assert #define alloc_assert(x) assert(x != NULL) #if defined __GNUC__ || defined __llvm__ || defined __clang__ |
