aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-08-07 18:16:54 -0700
committerGarrett D'Amore <garrett@damore.org>2017-08-07 18:16:54 -0700
commit491f1c1a5a209545287f9cc79f59ee816f5b9a41 (patch)
treeeecce44404886f4b85c3d45d867424d62a6b592d
parent705d39a6daf99b44c820631f04a116cc09b134b5 (diff)
downloadnng-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.c77
-rw-r--r--tests/CMakeLists.txt6
-rw-r--r--tests/compat_msg.c129
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;
+}
+