diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-08-07 18:16:54 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-08-07 18:16:54 -0700 |
| commit | 491f1c1a5a209545287f9cc79f59ee816f5b9a41 (patch) | |
| tree | eecce44404886f4b85c3d45d867424d62a6b592d | |
| parent | 705d39a6daf99b44c820631f04a116cc09b134b5 (diff) | |
| download | nng-491f1c1a5a209545287f9cc79f59ee816f5b9a41.tar.gz nng-491f1c1a5a209545287f9cc79f59ee816f5b9a41.tar.bz2 nng-491f1c1a5a209545287f9cc79f59ee816f5b9a41.zip | |
Fix crash when using legacy send API with NN_MSG.
We introduced the compat_msg.c from the old msg.c in the nanomsg
repo. While here, we found that the handling for send() was badly
wrong, by a level of indirection. We simplified the code to so that
nn_send() and nn_recv() are simple wrappers around the nn_sendmsg()
and nn_recvmsg() APIs (as in old nanomsg). This may not be quite as
fast, but it's more likely to be correct and reduces complexity.
| -rw-r--r-- | src/nng_compat.c | 77 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | tests/compat_msg.c | 129 |
3 files changed, 158 insertions, 54 deletions
diff --git a/src/nng_compat.c b/src/nng_compat.c index 523358f3..9515dc31 100644 --- a/src/nng_compat.c +++ b/src/nng_compat.c @@ -1,5 +1,6 @@ // // Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2017 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 @@ -255,24 +256,19 @@ nn_flags(int flags) int nn_send(int s, const void *buf, size_t len, int flags) { - int rv; + int rv; + struct nn_iovec iov; + struct nn_msghdr hdr; - if ((flags = nn_flags(flags)) == -1) { - return (-1); - } - if (len == NN_MSG) { - nng_msg *msg; - memcpy(&msg, ((char *) buf) - sizeof(msg), sizeof(msg)); - len = nng_msg_len(msg); - rv = nng_sendmsg((nng_socket) s, msg, flags); - } else { - rv = nng_send((nng_socket) s, (void *) buf, len, flags); - } - if (rv != 0) { - nn_seterror(rv); - return (-1); - } - return ((int) len); + iov.iov_base = (void *) buf; + iov.iov_len = len; + + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = NULL; + hdr.msg_controllen = 0; + + return (nn_sendmsg(s, &hdr, flags)); } int @@ -280,42 +276,18 @@ nn_recv(int s, void *buf, size_t len, int flags) { int rv; - if ((flags = nn_flags(flags)) == -1) { - return (-1); - } + struct nn_iovec iov; + struct nn_msghdr hdr; - if (len == NN_MSG) { - nng_msg *msg; + iov.iov_base = buf; + iov.iov_len = len; - if ((rv = nng_recvmsg((nng_socket) s, &msg, flags)) != 0) { - nn_seterror(rv); - return (-1); - } - - // prepend our header to the body... - // Note that this *can* alter the message, - // although for performance reasons it ought not. - // (There should be sufficient headroom.) - if ((rv = nng_msg_prepend(msg, &msg, sizeof(msg))) != 0) { - nng_msg_free(msg); - nn_seterror(rv); - return (-1); - } + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = NULL; + hdr.msg_controllen = 0; - // now "trim" it off... the value is still there, but the - // contents are unreferenced. We rely on legacy nanomsg's - // ignorance of nng msgs to preserve this. - nng_msg_trim(msg, sizeof(msg)); - - *(void **) buf = nng_msg_body(msg); - return ((int) nng_msg_len(msg)); - } - - if ((rv = nng_recv((nng_socket) s, buf, &len, flags)) != 0) { - nn_seterror(rv); - return (-1); - } - return ((int) len); + return (nn_recvmsg(s, &hdr, flags)); } int @@ -463,8 +435,9 @@ nn_sendmsg(int s, const struct nn_msghdr *mh, int flags) } if ((mh->msg_iovlen == 1) && (mh->msg_iov[0].iov_len == NN_MSG)) { - msg = *(nng_msg **) (((char *) mh->msg_iov[0].iov_base) - - sizeof(msg)); + char *bufp = *(char **) (mh->msg_iov[0].iov_base); + + msg = *(nng_msg **) (bufp - sizeof(msg)); keep = 1; // keep the message on error } else { char *ptr; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5dcc1379..47c086d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,8 +2,9 @@ # Copyright (c) 2012 Martin Sustrik All rights reserved. # Copyright (c) 2013 GoPivotal, Inc. All rights reserved. # Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. -# Copyright 2017 Garrett D'Amore <garrett@damore.org> # Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com> +# Copyright 2017 Garrett D'Amore <garrett@damore.org> +# Copyright 2017 Capitar IT Group BV <info@capitar.com> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), @@ -60,7 +61,7 @@ if (NNG_TESTS) target_link_libraries (${NAME} "${CMAKE_THREAD_LIBS_INIT}") endif() - add_test (NAME ${NAME} COMMAND ${NAME} -v ${TEST_PORT}) + add_test (NAME ${NAME} COMMAND ${NAME} ${TEST_PORT}) set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT}) math (EXPR TEST_PORT "${TEST_PORT}+10") endmacro (add_nng_compat_test) @@ -92,5 +93,6 @@ add_nng_compat_test(compat_block 5) add_nng_compat_test(compat_bug777 5) add_nng_compat_test(compat_bus 5) add_nng_compat_test(compat_cmsg 5) +add_nng_compat_test(compat_msg 5) add_nng_compat_test(compat_device 5) add_nng_compat_test(compat_reqrep 5) diff --git a/tests/compat_msg.c b/tests/compat_msg.c new file mode 100644 index 00000000..683739d3 --- /dev/null +++ b/tests/compat_msg.c @@ -0,0 +1,129 @@ +/* + Copyright (c) 2013 Martin Sustrik All rights reserved. + Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com> + Copyright 2017 Garrett D'Amore <garrett@damore.org> + Copyright 2017 Capitar IT Group BV <info@capitar.com> + + 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. +*/ + +#include "nng_compat.h" +#include "compat_testutil.h" + +#include <string.h> + +#define SOCKET_ADDRESS "inproc://a" + +char longdata[1 << 20]; + +int main (int argc, const char *argv[]) +{ + int rc; + int sb; + int sc; + unsigned char *buf1, *buf2; + int i; + struct nn_iovec iov; + struct nn_msghdr hdr; + char socket_address_tcp[128]; + + test_addr_from(socket_address_tcp, "tcp", "127.0.0.1", + get_test_port(argc, argv)); + + sb = test_socket (AF_SP, NN_PAIR); + test_bind (sb, SOCKET_ADDRESS); + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, SOCKET_ADDRESS); + + buf1 = nn_allocmsg (256, 0); + alloc_assert (buf1); + for (i = 0; i != 256; ++i) + buf1 [i] = (unsigned char) i; + rc = nn_send (sc, &buf1, NN_MSG, 0); + errno_assert (rc >= 0); + nn_assert (rc == 256); + + buf2 = NULL; + rc = nn_recv (sb, &buf2, NN_MSG, 0); + errno_assert (rc >= 0); + nn_assert (rc == 256); + nn_assert (buf2); + for (i = 0; i != 256; ++i) + nn_assert (buf2 [i] == (unsigned char) i); + rc = nn_freemsg (buf2); + errno_assert (rc == 0); + + buf1 = nn_allocmsg (256, 0); + alloc_assert (buf1); + for (i = 0; i != 256; ++i) + buf1 [i] = (unsigned char) i; + iov.iov_base = &buf1; + iov.iov_len = NN_MSG; + memset (&hdr, 0, sizeof (hdr)); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + rc = nn_sendmsg (sc, &hdr, 0); + errno_assert (rc >= 0); + nn_assert (rc == 256); + + buf2 = NULL; + iov.iov_base = &buf2; + iov.iov_len = NN_MSG; + memset (&hdr, 0, sizeof (hdr)); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + rc = nn_recvmsg (sb, &hdr, 0); + errno_assert (rc >= 0); + nn_assert (rc == 256); + nn_assert (buf2); + for (i = 0; i != 256; ++i) + nn_assert (buf2 [i] == (unsigned char) i); + rc = nn_freemsg (buf2); + errno_assert (rc == 0); + + test_close (sc); + test_close (sb); + + /* Test receiving of large message */ + + sb = test_socket (AF_SP, NN_PAIR); + test_bind (sb, socket_address_tcp); + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, socket_address_tcp); + + for (i = 0; i < (int) sizeof (longdata); ++i) + longdata[i] = '0' + (i % 10); + longdata [sizeof (longdata) - 1] = 0; + test_send (sb, longdata); + + rc = nn_recv (sc, &buf2, NN_MSG, 0); + errno_assert (rc >= 0); + nn_assert (rc == sizeof (longdata) - 1); + nn_assert (buf2); + for (i = 0; i < (int) sizeof (longdata) - 1; ++i) + nn_assert (buf2 [i] == longdata [i]); + rc = nn_freemsg (buf2); + errno_assert (rc == 0); + + test_close (sc); + test_close (sb); + + return 0; +} + |
