aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/man/nngcat.1.adoc39
-rw-r--r--src/transport/ipc/ipc.c2
-rw-r--r--src/transport/tcp/tcp.c2
-rw-r--r--src/transport/tls/tls.c2
-rw-r--r--src/transport/zerotier/zerotier.c3
-rw-r--r--tools/nngcat/CMakeLists.txt17
-rw-r--r--tools/nngcat/nngcat.c119
-rw-r--r--tools/nngcat/nngcat_ambiguous_test.sh29
-rw-r--r--tools/nngcat/nngcat_async_test.sh31
-rw-r--r--tools/nngcat/nngcat_dup_proto_test.sh21
-rw-r--r--tools/nngcat/nngcat_help_test.sh30
-rw-r--r--tools/nngcat/nngcat_incompat_test.sh72
-rw-r--r--tools/nngcat/nngcat_need_proto_test.sh21
-rw-r--r--tools/nngcat/nngcat_pubsub_test.sh43
-rw-r--r--tools/nngcat/nngcat_recvmaxsz_test.sh44
-rw-r--r--tools/nngcat/nngcat_unlimited_test.sh44
16 files changed, 476 insertions, 43 deletions
diff --git a/docs/man/nngcat.1.adoc b/docs/man/nngcat.1.adoc
index 4bbaf002..dd80c94a 100644
--- a/docs/man/nngcat.1.adoc
+++ b/docs/man/nngcat.1.adoc
@@ -19,7 +19,7 @@ nngcat - command line access to Scalabity Protocols
*nngcat* --version
-*nngcat* [_OPTION_]...
+*nngcat* [_OPTION_]...
== DESCRIPTION
@@ -55,12 +55,16 @@ each option must be presented as a separate argument to the program.
=== Generic Options
*-h, --help*::
Get usage help.
+
*-V, --version*::
Print the version and exit.
+
*-v, --verbose*::
Select verbose operation.
+
*-q, --silent*::
Select silent operation.
+
*--compat*::
Compatible mode. (((compatible mode)))
This cause _nngcat_ to behave more like the legacy
@@ -68,6 +72,7 @@ each option must be presented as a separate argument to the program.
In this mode connections are made asynchronously,
and the *--pair* option selects version 0 of
the <<nng_pair.7#,_pair_>> protocol instead of version 1.
+
*--subscribe*=_TOPIC_::
Subscribe to _TOPIC_. This option can only be used with the
<<nng_sub.7#,_sub_>> protocol.
@@ -76,6 +81,17 @@ each option must be presented as a separate argument to the program.
This may be specified multiple times to subscribe to multiple topics.
If not specified at all, then a default subscription to everything is assumed.
+*--count=*=_COUNT_::
+ Limit the number of iterations when looping to _COUNT_ iterations.
+ For protocols that only send, this will only send _COUNT_ messages before
+ exiting.
+ For protocols that only receive, this will only receive _COUNT_ messages
+ before exiting.
+ For protocols that involve a full exchange, this will only perform _COUNT_
+ exchanges (each exchange is characterized by at most a single send, and
+ one or more receives.)
+ If _COUNT_ is zero, then an infinite number of iterations is performed.
+
=== Protocol Selection Options
NOTE: At least one protocol must be selected.
@@ -102,7 +118,7 @@ NOTE: At least one protocol must be selected.
Select the <<nng_sub.7#,_sub_>> version 0 protocol.
This protocol receives messages from <<nng_pub.7#,_pub_>> version
0 peers, and filters them based on subscriptions set with *--subscribe*.
-
+
*--push, --push0*::
Select the <<nng_push.7#,_push_>> version 0 protocol.
This protocol sends messages to <<nng_pull.7#,_pull_>> version 0 peers.
@@ -123,7 +139,7 @@ NOTE: At least one protocol must be selected.
This protocol can send and receive messages with one connected _pair_
version 1 peer.
It is not supported in *--compat* mode.
- (Polyamorous mode is not supported
+ (Polyamorous mode is not supported
in _nngcat_, although peers may be using polyamorous mode.)
*--pair*::
@@ -153,11 +169,11 @@ more than one peer on a given connection.
Bind to, and accept connections from peers, at the address specified by _URL_.
*-x, --connect-ipc*=_PATH_::
- Connect to the IPC path specified by _PATH_. This is the same as
+ Connect to the IPC path specified by _PATH_. This is the same as
*--connect*=ipc://_PATH_.
*-X, --bind-ipc*=_PATH_::
- Bind to the IPC path specified by _PATH_. This is the same as
+ Bind to the IPC path specified by _PATH_. This is the same as
*--bind*=ipc://_PATH_.
*-l, --connect-local*=_PORT_::
@@ -165,7 +181,7 @@ more than one peer on a given connection.
as *--connect*=tcp://127.0.0.1:__PORT__.
*-L, --bind-local*=_PORT_::
- Bind to the TCP port specified by _PORT_. This is the same as
+ Bind to the TCP port specified by _PORT_. This is the same as
*--bind*=tcp://127.0.0.1:__PORT__.
=== Receive Options
@@ -212,9 +228,15 @@ options can only be specified when using a protocol that receives messages.
Give up receiving messages after _SEC_ seconds pass without any received
messages.
+*--recv-maxsz*=_COUNT_::
+ Set the maximum message size socket will accept to _COUNT_ bytes.
+ Messages larger than this will be discarded.
+ The default is 1048576 (1 MB).
+ To eliminate any restriction, use 0.
+
=== Transmit Options
-Protocols that support sending data can use these options to select the data.
+Protocols that support sending data can use these options to select the data.
*-D, --data*=_DATA_::
Use _DATA_ for the body of outgoing messages.
@@ -249,7 +271,7 @@ when using addresses that are not secured with TLS.
*--key*=_FILE_::
Load own key from _FILE_.
Should be used in conjuction with *--cert*.
- If not specified, and *--cert* is specified, then a single file containing both
+ If not specified, and *--cert* is specified, then a single file containing both
the private key and the associated certificate is assumed.
*--cacert*=_FILE_::
@@ -303,4 +325,3 @@ $ nngcat --sub --dial=${addr} --quoted &
<<nng_req.7#,nng_req(7)>>,
<<nng_respondent.7#,nng_respondent(7)>>,
<<nng_surveyor.7#,nng_surveyor(7)>>
-
diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c
index e5f3d533..c91606c6 100644
--- a/src/transport/ipc/ipc.c
+++ b/src/transport/ipc/ipc.c
@@ -302,7 +302,7 @@ nni_ipc_pipe_recv_cb(void *arg)
// Make sure the message payload is not too big. If it is
// the caller will shut down the pipe.
- if (len > pipe->rcvmax) {
+ if ((len > pipe->rcvmax) && (pipe->rcvmax > 0)) {
rv = NNG_EMSGSIZE;
goto recv_error;
}
diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c
index d7920f72..3d738a98 100644
--- a/src/transport/tcp/tcp.c
+++ b/src/transport/tcp/tcp.c
@@ -299,7 +299,7 @@ nni_tcp_pipe_recv_cb(void *arg)
// Make sure the message payload is not too big. If it is
// the caller will shut down the pipe.
- if (len > p->rcvmax) {
+ if ((len > p->rcvmax) && (p->rcvmax > 0)) {
rv = NNG_EMSGSIZE;
goto recv_error;
}
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c
index 73d1a29b..78fdd622 100644
--- a/src/transport/tls/tls.c
+++ b/src/transport/tls/tls.c
@@ -307,7 +307,7 @@ nni_tls_pipe_recv_cb(void *arg)
// Make sure the message payload is not too big. If it is
// the caller will shut down the pipe.
- if (len > p->rcvmax) {
+ if ((len > p->rcvmax) && (p->rcvmax > 0)) {
rv = NNG_EMSGSIZE;
goto recv_error;
}
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index 05866cfb..73cddf7d 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -921,7 +921,8 @@ zt_pipe_recv_data(zt_pipe *p, const uint8_t *data, size_t len)
if (fragno == (nfrags - 1)) {
// Last frag, maybe shorten the message.
nni_msg_chop(fl->fl_msg, (fragsz - len));
- if (nni_msg_len(fl->fl_msg) > p->zp_rcvmax) {
+ if ((nni_msg_len(fl->fl_msg) > p->zp_rcvmax) &&
+ (p->zp_rcvmax > 0)) {
// Strict enforcement of max recv.
zt_fraglist_clear(fl);
// Just discard the message.
diff --git a/tools/nngcat/CMakeLists.txt b/tools/nngcat/CMakeLists.txt
index 3864c8e4..bcd356ee 100644
--- a/tools/nngcat/CMakeLists.txt
+++ b/tools/nngcat/CMakeLists.txt
@@ -13,4 +13,21 @@ if (NNG_ENABLE_NNGCAT)
target_include_directories (nngcat PUBLIC ${PROJECT_SOURCE_DIR}/src)
target_link_libraries (nngcat ${PROJECT_NAME})
install (TARGETS nngcat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+ if (NNG_TESTS AND NNG_PLATFORM_POSIX)
+ macro(add_nngcat_test NAME TIMEOUT)
+ file (COPY ${NAME}_test.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+ add_test (NAME ${NAME} COMMAND bash ${NAME}_test.sh)
+ set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
+ endmacro()
+ add_nngcat_test (nngcat_async 10)
+ add_nngcat_test (nngcat_ambiguous 2)
+ add_nngcat_test (nngcat_need_proto 2)
+ add_nngcat_test (nngcat_dup_proto 2)
+ add_nngcat_test (nngcat_help 2)
+ add_nngcat_test (nngcat_incompat 2)
+ add_nngcat_test (nngcat_pubsub 20)
+ add_nngcat_test (nngcat_recvmaxsz 20)
+ add_nngcat_test (nngcat_unlimited 20)
+ endif()
endif()
diff --git a/tools/nngcat/nngcat.c b/tools/nngcat/nngcat.c
index c8a73859..132599e4 100644
--- a/tools/nngcat/nngcat.c
+++ b/tools/nngcat/nngcat.c
@@ -53,6 +53,8 @@ size_t keylen = 0;
void * certfile = NULL;
size_t certlen = 0;
const char * zthome = NULL;
+int count = 0;
+int recvmaxsz = -1;
// Options, must start at 1 because zero is sentinel.
enum options {
@@ -78,6 +80,7 @@ enum options {
OPT_SUBSCRIBE,
OPT_INTERVAL,
OPT_DELAY,
+ OPT_COUNT,
OPT_FORMAT,
OPT_RAW,
OPT_ASCII,
@@ -99,6 +102,7 @@ enum options {
OPT_KEYFILE,
OPT_CERTFILE,
OPT_VERSION,
+ OPT_RECVMAXSZ,
OPT_ZTHOME,
};
@@ -132,6 +136,18 @@ static nng_optspec opts[] = {
{ .o_name = "compat", .o_val = OPT_COMPAT },
{ .o_name = "async", .o_val = OPT_ASYNC },
{
+ .o_name = "recv-maxsz",
+ .o_short = 'Z',
+ .o_val = OPT_RECVMAXSZ,
+ .o_arg = true,
+ },
+ {
+ .o_name = "count",
+ .o_short = 'C',
+ .o_val = OPT_COUNT,
+ .o_arg = true,
+ },
+ {
.o_name = "delay",
.o_short = 'd',
.o_val = OPT_DELAY,
@@ -238,8 +254,18 @@ help(void)
printf(" --subscribe <topic> (only with --sub protocol)\n");
printf(" --silent (or alias -q)\n");
printf(" --verbose (or alias -v)\n");
+ printf(" --count <num> (or alias -C <num>)\n");
+ printf(" --delay <secs> (or alias -d <secs>)\n");
+ printf(" --interval <secs> (or alias -i <secs>)\n");
+ printf(" --recv-timeout <secs>\n");
+ printf(" --send-timeout <secs>\n");
+ printf(" --recv-maxsz <size> (or alias -Z <size>)\n");
printf(" --compat\n");
printf(" --async\n");
+ printf(" --insecure (or alias -k)\n");
+ printf(" --cacert <file>\n");
+ printf(" --cert <file> (or alias -E <file>)\n");
+ printf(" --key <file>\n");
printf(" --zt-home <path>\n");
printf("\n<src> may be one of:\n");
printf(" --file <file> (or alias -F <file>)\n");
@@ -279,38 +305,24 @@ static void
loadfile(const char *path, void **datap, size_t *lenp)
{
FILE * f;
- size_t cap;
char * data;
size_t len;
+
if ((f = fopen(path, "r")) == NULL) {
fatal("Cannot open file %s: %s", path, strerror(errno));
}
- cap = 4096;
- len = 0;
- if ((data = malloc(cap)) == NULL) {
+ if (fseek(f, 0, SEEK_END) != 0) {
+ fatal("Cannot seek to end of file: %s", strerror(errno));
+ }
+ len = ftell(f);
+ (void) fseek(f, 0, SEEK_SET);
+ if ((data = malloc(len + 1)) == NULL) {
fatal("Out of memory.");
}
- data[0] = '\0';
- for (;;) {
- size_t n;
- // Read until end of file, reallocating as needed.
- if (len == (cap - 1)) {
- void *old = data;
- cap *= 2;
- if ((data = realloc(old, cap)) == NULL) {
- fatal("Out of memory");
- }
- }
- n = fread(data + len, 1, cap - len, f);
- if (n == 0) {
- if (ferror(f)) {
- fatal("Read file %s failed: %s", path,
- strerror(errno));
- }
- break;
- }
- len += n;
- data[len] = '\0';
+ data[len] = '\0';
+
+ if (fread(data, 1, len, f) != len) {
+ fatal("Read file %s failed: %s", path, strerror(errno));
}
fclose(f);
*datap = data;
@@ -462,11 +474,16 @@ printmsg(char *buf, size_t len)
void
recvloop(nng_socket sock)
{
+ int iters = 0;
for (;;) {
int rv;
nng_msg *msg;
+ if ((count > 0) && (iters >= count)) {
+ break;
+ }
rv = nng_recvmsg(sock, &msg, 0);
+ iters++;
switch (rv) {
case NNG_ETIMEDOUT:
case NNG_ESTATE:
@@ -486,6 +503,7 @@ recvloop(nng_socket sock)
void
resploop(nng_socket sock)
{
+ int iters = 0;
for (;;) {
int rv;
nng_msg *msg;
@@ -502,12 +520,21 @@ resploop(nng_socket sock)
if ((rv = nng_sendmsg(sock, msg, 0)) != 0) {
fatal("Send error: %s", nng_strerror(rv));
}
+
+ iters++;
+ if ((count > 0) && (iters >= count)) {
+ break;
+ }
}
+
+ nng_msleep(200);
}
void
sendloop(nng_socket sock)
{
+ int iters = 0;
+
if (data == NULL) {
fatal("No data to send (specify with --data or --file)");
}
@@ -533,10 +560,13 @@ sendloop(nng_socket sock)
end = nng_clock();
delta = (nng_duration)(end - start);
+ iters++;
// By default, we don't loop.
- if (interval < 0) {
+ if (((interval < 0) && (count == 0)) ||
+ ((count > 0) && (iters >= count))) {
break;
}
+
// We sleep, but we account for time spent, so that our
// interval appears more or less constant. Of course
// if we took more than the interval here, then we skip
@@ -545,11 +575,15 @@ sendloop(nng_socket sock)
nng_msleep(interval - delta);
}
}
+ // Wait a bit to give queues a chance to drain.
+ nng_msleep(200);
}
void
sendrecv(nng_socket sock)
{
+ int iters = 0;
+
if (data == NULL) {
fatal("No data to send (specify with --data or --file)");
}
@@ -575,7 +609,7 @@ sendrecv(nng_socket sock)
if ((rv = nng_sendmsg(sock, msg, 0)) != 0) {
fatal("Send error: %s", nng_strerror(rv));
}
- if (interval < 0) {
+ if ((interval < 0) && (count == 0)) {
// Only one iteration through.
recvloop(sock);
break;
@@ -583,7 +617,8 @@ sendrecv(nng_socket sock)
// We would like to use recvloop, but we need to reset
// our timeout each time, as the timer counts down
- // towards zero.
+ // towards zero. Furthermore, with survey, we don't
+ // want to increment the iteration count.
for (;;) {
delta = (nng_duration)(nng_clock() - start);
@@ -620,6 +655,11 @@ sendrecv(nng_socket sock)
end = nng_clock();
delta = (nng_duration)(end - start);
+ iters++;
+ if ((count > 0) && (iters >= count)) {
+ break;
+ }
+
// We sleep, but we account for time spent, so that our
// interval appears more or less constant. Of course
// if we took more than the interval here, then we skip
@@ -687,6 +727,9 @@ main(int ac, const char **av)
snprintf(scratch, sizeof(scratch), "ipc:///%s", arg);
addrend = addaddr(addrend, val, scratch);
break;
+ case OPT_COUNT:
+ count = intarg(arg, 0x7fffffff);
+ break;
case OPT_SUBSCRIBE:
topicend = addtopic(topicend, arg);
break;
@@ -706,6 +749,12 @@ main(int ac, const char **av)
case OPT_RCV_TIMEO:
recvtimeo = intarg(arg, 86400) * 1000; // max 1 day
break;
+ case OPT_RECVMAXSZ:
+ recvmaxsz = intarg(arg, 0x7fffffff);
+ if (recvmaxsz == 0) {
+ recvmaxsz = 0x7fffffff;
+ }
+ break;
case OPT_COMPAT:
compat = 1;
break;
@@ -815,7 +864,11 @@ main(int ac, const char **av)
if (compat) {
if (async != 0) {
- fatal("Option --async and --compat are "
+ fatal("Options --async and --compat are "
+ "incompatible.");
+ }
+ if (count != 0) {
+ fatal("Options --count and --compat are "
"incompatible.");
}
if (proto == OPT_PAIR) {
@@ -990,6 +1043,12 @@ main(int ac, const char **av)
fatal("Unable to set send timeout: %s", nng_strerror(rv));
}
+ if ((recvmaxsz >= 0) &&
+ ((rv = nng_setopt_size(sock, NNG_OPT_RECVMAXSZ, recvmaxsz)) !=
+ 0)) {
+ fatal("Unable to set max receive size: %s", nng_strerror(rv));
+ }
+
for (struct addr *a = addrs; a != NULL; a = a->next) {
char * act;
nng_listener l;
@@ -1109,7 +1168,7 @@ main(int ac, const char **av)
sendrecv(sock);
break;
default:
- fatal("Protocol handling unimplmented.");
+ fatal("Protocol handling unimplemented.");
}
exit(0);
diff --git a/tools/nngcat/nngcat_ambiguous_test.sh b/tools/nngcat/nngcat_ambiguous_test.sh
new file mode 100644
index 00000000..54aec7f5
--- /dev/null
+++ b/tools/nngcat/nngcat_ambiguous_test.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+NNGCAT=${NNGCAT:-./nngcat}
+CMD="${NNGCAT} --re --dial=tcp://127.0.0.1:27272"
+echo -n "Verify ambiguous options fail: "
+if ${CMD} >/dev/null 2>&1
+then
+ echo "Failed: ambigous accepted"
+ exit 1
+fi
+x=$(${CMD} 2>&1)
+if [[ ${x} =~ "ambiguous" ]]
+then
+ echo "pass"
+ exit 0
+fi
+
+echo "Failed: error did not match"
+exit 1
diff --git a/tools/nngcat/nngcat_async_test.sh b/tools/nngcat/nngcat_async_test.sh
new file mode 100644
index 00000000..527c92d1
--- /dev/null
+++ b/tools/nngcat/nngcat_async_test.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+echo -n "Verify async connect: "
+
+NNGCAT=${NNGCAT:-./nngcat}
+ADDR="ipc:///tmp/nngcat_async_test"
+
+${NNGCAT} --async -d 1 --connect ${ADDR} --req0 -D "ping" &
+
+
+answer=$( ${NNGCAT} --rep0 --recv-timeout=3 --listen ${ADDR} -D "pong" --ascii 2>/dev/null )
+
+if [[ ${answer} == "ping" ]]
+then
+ echo "pass"
+ exit 0
+fi
+
+echo "Failed: req did not match"
+echo "RES: $answer"
+exit 1
diff --git a/tools/nngcat/nngcat_dup_proto_test.sh b/tools/nngcat/nngcat_dup_proto_test.sh
new file mode 100644
index 00000000..8ba9c3d6
--- /dev/null
+++ b/tools/nngcat/nngcat_dup_proto_test.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+NNGCAT=${NNGCAT:-./nngcat}
+echo -n "Verify only a single protocol is allowed: "
+if ${NNGCAT} --pub0 --sub0 --dial=tcp://127.0.0.1:8989 >/dev/null 2>&1
+then
+ echo "Failed: duplicate protocols accepted"
+ exit 1
+fi
+echo "pass"
+exit 0
diff --git a/tools/nngcat/nngcat_help_test.sh b/tools/nngcat/nngcat_help_test.sh
new file mode 100644
index 00000000..2629633e
--- /dev/null
+++ b/tools/nngcat/nngcat_help_test.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+NNGCAT=${NNGCAT:-./nngcat}
+echo -n "Verify nngcat help: "
+if ${NNGCAT} --help >/dev/null 2>&1
+then
+ echo "Failed: help didn't return 1"
+ exit 1
+fi
+x=$(${NNGCAT} --help 2>&1)
+if [[ ${x} =~ "Usage:" ]]
+then
+ echo "pass"
+ exit 0
+fi
+
+echo "Failed: usage did not match"
+echo "Output:"
+echo "$x"
+exit 1
diff --git a/tools/nngcat/nngcat_incompat_test.sh b/tools/nngcat/nngcat_incompat_test.sh
new file mode 100644
index 00000000..fcadef80
--- /dev/null
+++ b/tools/nngcat/nngcat_incompat_test.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+NNGCAT=${NNGCAT:-./nngcat}
+echo "Verify incompatible options: "
+
+# Just bind something to this so other ones connect
+${NNGCAT} --pull0 --ascii -X /tmp/bogusipc &
+pid=$!
+
+trap "kill $pid && wait $pid 2>/dev/null" 0
+
+echo -n " --subscribe doesn't work with non-sub"
+if ${NNGCAT} --req0 -x /tmp/bogusipc --subscribe=oops >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo -n " --interval doesn't work with recv only: "
+if ${NNGCAT} --interval 1 --pull -x /tmp/bogusipc >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo -n " --pair1 doesn't work with --compat: "
+if ${NNGCAT} --compat --pair1 -x /tmp/bogusipc >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo -n " --count doesn't work with --compat: "
+if ${NNGCAT} --compat --count=1 --pair0 -x /tmp/bogusipc >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo -n " --count fails with non-integer: "
+if ${NNGCAT} --count=xyz --pair0 -x /tmp/bogusipc >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo -n " --file fails with non-existing file: "
+if ${NNGCAT} --async --file=/nosuchfilehere --push0 -x /tmp/bogusipc >/dev/null 2>&1
+then
+ echo "fail"
+ exit 1
+fi
+echo "pass"
+
+echo "PASS."
+exit 0
+
diff --git a/tools/nngcat/nngcat_need_proto_test.sh b/tools/nngcat/nngcat_need_proto_test.sh
new file mode 100644
index 00000000..791b8c4b
--- /dev/null
+++ b/tools/nngcat/nngcat_need_proto_test.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+NNGCAT=${NNGCAT:-./nngcat}
+echo -n "Verify a protocol is needed: "
+if ${NNGCAT} --dial=tcp://127.0.0.1:8989 >/dev/null 2>&1
+then
+ echo "Failed: protocol should be required"
+ exit 1
+fi
+echo "pass"
+exit 0
diff --git a/tools/nngcat/nngcat_pubsub_test.sh b/tools/nngcat/nngcat_pubsub_test.sh
new file mode 100644
index 00000000..a28cf865
--- /dev/null
+++ b/tools/nngcat/nngcat_pubsub_test.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+echo -n "Verify pub sub: "
+
+NNGCAT=${NNGCAT:-./nngcat}
+ADDR="ipc:///tmp/nngcat_pub_sub_test"
+OUTPUT=/tmp/nngcat_pubsub_test.$$.out
+trap "rm $OUTPUT" 0
+
+${NNGCAT} --listen ${ADDR} --count=3 --recv-timeout=20 --sub0 --subscribe=one --subscribe=two --quoted > $OUTPUT 2>/dev/null &
+sleep 1
+# for speed of execution, run these in the background, they should be ignored
+${NNGCAT} -d 1 --connect ${ADDR} --pub0 --data "xyz" &
+${NNGCAT} -d 1 --connect ${ADDR} --pub0 -D "none swam" &
+# these we care about, due to ordering (checksum) so run them serially
+${NNGCAT} -d 1 --connect ${ADDR} --pub0 -D "one flew"
+${NNGCAT} -d 1 --connect ${ADDR} --pub0 --data "twofer test"
+${NNGCAT} -d 1 --connect ${ADDR} --pub0 --data "one more"
+
+wait $bgid 2>/dev/null
+
+sum=$(cksum ${OUTPUT})
+sum=${sum%% *}
+if [[ ${sum} == 3929078614 ]]
+then
+ echo "pass"
+ exit 0
+fi
+echo "FAIL: Checksum failed (Wanted 3929078614 got ${sum})"
+echo "OUTPUT:"
+cat ${OUTPUT}
+
+exit 1
diff --git a/tools/nngcat/nngcat_recvmaxsz_test.sh b/tools/nngcat/nngcat_recvmaxsz_test.sh
new file mode 100644
index 00000000..d77a5658
--- /dev/null
+++ b/tools/nngcat/nngcat_recvmaxsz_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+echo -n "Verify maximum receive size: "
+
+NNGCAT=${NNGCAT:-./nngcat}
+ADDR="ipc:///tmp/nngcat_recvmaxsz_test"
+OUTPUT=/tmp/nngcat_recvmaxsz_test.$$.out
+trap "rm $OUTPUT" 0
+
+${NNGCAT} --listen ${ADDR} --count=3 --recv-maxsz=5 --pull0 --quoted > $OUTPUT 2>/dev/null &
+sleep 1
+# for speed of execution, run these in the background, they should be ignored
+${NNGCAT} --connect ${ADDR} --push0 --data "one"
+${NNGCAT} --connect ${ADDR} --push0 --data "55555"
+${NNGCAT} --connect ${ADDR} --push0 --data "666666"
+${NNGCAT} --connect ${ADDR} --push0 --data "7777777"
+${NNGCAT} --connect ${ADDR} --push0 --data "88888"
+
+wait $bgid 2>/dev/null
+
+sum=$(cksum ${OUTPUT})
+sum=${sum%% *}
+
+# This matches 3 lines of "one", "55555", "88888".
+if [[ ${sum} == 4122906158 ]]
+then
+ echo "pass"
+ exit 0
+fi
+echo "FAIL: Checksum failed (Wanted 3929078614 got ${sum})"
+echo "OUTPUT:"
+cat ${OUTPUT}
+
+exit 1
diff --git a/tools/nngcat/nngcat_unlimited_test.sh b/tools/nngcat/nngcat_unlimited_test.sh
new file mode 100644
index 00000000..7b5b4f2c
--- /dev/null
+++ b/tools/nngcat/nngcat_unlimited_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+#
+# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+# Copyright 2018 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
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+echo -n "Verify unlimited receive size: "
+
+NNGCAT=${NNGCAT:-./nngcat}
+ADDR="ipc:///tmp/nngcat_unlimited_test"
+INPUT=/tmp/nngcat_unlimited_test.$$.in
+OUTPUT=/tmp/nngcat_unlimited_test.$$.out
+trap "rm $OUTPUT $INPUT" 0
+
+# 4 MB
+dd if=/dev/urandom of=${INPUT} bs=1024 count=4096 >/dev/null 2>&1
+goodsum=$(cksum ${INPUT})
+goodsum=${goodsum%% *}
+
+${NNGCAT} --listen ${ADDR} --count=1 --recv-maxsz=0 --pull0 --raw > $OUTPUT 2>/dev/null &
+sleep 1
+# for speed of execution, run these in the background, they should be ignored
+${NNGCAT} --connect ${ADDR} --push0 --file ${INPUT}
+wait $bgid 2>/dev/null
+
+sum=$(cksum ${OUTPUT})
+sum=${sum%% *}
+
+if [[ ${sum} == ${goodsum} ]]
+then
+ echo "pass"
+ exit 0
+fi
+echo "FAIL: Checksum failed (Wanted ${goodsum} got ${sum})"
+echo "OUTPUT:"
+ls -la ${OUTPUT}
+
+exit 1