diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-08-14 15:27:38 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-08-14 15:27:38 -0700 |
| commit | 63479c2938cbc80c1aac9367cb95564f6e7540e1 (patch) | |
| tree | 495584b637f73b593d25f01577eeaa944477f159 | |
| parent | 343417234aa3fd86e8ae0b56ae500a1ed3411cfc (diff) | |
| download | nng-63479c2938cbc80c1aac9367cb95564f6e7540e1.tar.gz nng-63479c2938cbc80c1aac9367cb95564f6e7540e1.tar.bz2 nng-63479c2938cbc80c1aac9367cb95564f6e7540e1.zip | |
fixes #63 NNG_FLAG_SYNCH should be the default
Also enables creating endpoints that are idle (first part of
endpoint options API) and shutting down endpoints.
| -rw-r--r-- | perf/perf.c | 9 | ||||
| -rw-r--r-- | src/core/endpt.c | 39 | ||||
| -rw-r--r-- | src/nng.c | 60 | ||||
| -rw-r--r-- | src/nng.h | 7 | ||||
| -rw-r--r-- | src/nng_compat.c | 5 | ||||
| -rw-r--r-- | src/transport/inproc/inproc.c | 1 | ||||
| -rw-r--r-- | tests/bus.c | 142 | ||||
| -rw-r--r-- | tests/device.c | 8 | ||||
| -rw-r--r-- | tests/event.c | 4 | ||||
| -rw-r--r-- | tests/pair1.c | 48 | ||||
| -rw-r--r-- | tests/pipeline.c | 14 | ||||
| -rw-r--r-- | tests/pubsub.c | 249 | ||||
| -rw-r--r-- | tests/reqrep.c | 6 | ||||
| -rw-r--r-- | tests/scalability.c | 4 | ||||
| -rw-r--r-- | tests/sock.c | 51 | ||||
| -rw-r--r-- | tests/survey.c | 9 | ||||
| -rw-r--r-- | tests/tcp.c | 6 | ||||
| -rw-r--r-- | tests/trantest.h | 19 |
18 files changed, 379 insertions, 302 deletions
diff --git a/perf/perf.c b/perf/perf.c index 2e631a01..1319fffc 100644 --- a/perf/perf.c +++ b/perf/perf.c @@ -219,7 +219,6 @@ do_inproc_lat(int argc, char **argv) ia.count = parse_int(argv[1], "count"); ia.func = latency_server; - if ((rv = nni_thr_init(&thr, do_inproc, &ia)) != 0) { die("Cannot create thread: %s", nng_strerror(rv)); } @@ -275,7 +274,7 @@ latency_client(const char *addr, int msgsize, int trips) // XXX: set no delay // XXX: other options (TLS in the future?, Linger?) - if ((rv = nng_dial(s, addr, NULL, NNG_FLAG_SYNCH)) != 0) { + if ((rv = nng_dial(s, addr, NULL, 0)) != 0) { die("nng_dial: %s", nng_strerror(rv)); } @@ -321,7 +320,7 @@ latency_server(const char *addr, int msgsize, int trips) // XXX: set no delay // XXX: other options (TLS in the future?, Linger?) - if ((rv = nng_listen(s, addr, NULL, NNG_FLAG_SYNCH)) != 0) { + if ((rv = nng_listen(s, addr, NULL, 0)) != 0) { die("nng_listen: %s", nng_strerror(rv)); } @@ -371,7 +370,7 @@ throughput_server(const char *addr, int msgsize, int count) // XXX: set no delay // XXX: other options (TLS in the future?, Linger?) - if ((rv = nng_listen(s, addr, NULL, NNG_FLAG_SYNCH)) != 0) { + if ((rv = nng_listen(s, addr, NULL, 0)) != 0) { die("nng_listen: %s", nng_strerror(rv)); } @@ -430,7 +429,7 @@ throughput_client(const char *addr, int msgsize, int count) die("nng_setopt(NNG_OPT_SNDBUF): %s", nng_strerror(rv)); } - if ((rv = nng_dial(s, addr, NULL, NNG_FLAG_SYNCH)) != 0) { + if ((rv = nng_dial(s, addr, NULL, 0)) != 0) { die("nng_dial: %s", nng_strerror(rv)); } diff --git a/src/core/endpt.c b/src/core/endpt.c index 6e5f7e8a..0ab35ea3 100644 --- a/src/core/endpt.c +++ b/src/core/endpt.c @@ -23,9 +23,9 @@ struct nni_ep { nni_sock * ep_sock; char ep_addr[NNG_MAXADDRLEN]; int ep_mode; + int ep_started; int ep_closed; // full shutdown int ep_closing; // close pending (waiting on refcnt) - int ep_bound; // true if we bound locally int ep_refcnt; nni_mtx ep_mtx; nni_cv ep_cv; @@ -132,13 +132,13 @@ nni_ep_create(nni_ep **epp, nni_sock *s, const char *addr, int mode) if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - ep->ep_closed = 0; - ep->ep_bound = 0; - ep->ep_data = NULL; - ep->ep_refcnt = 1; - ep->ep_sock = s; - ep->ep_tran = tran; - ep->ep_mode = mode; + ep->ep_closed = 0; + ep->ep_started = 0; + ep->ep_data = NULL; + ep->ep_refcnt = 1; + ep->ep_sock = s; + ep->ep_tran = tran; + ep->ep_mode = mode; // Make a copy of the endpoint operations. This allows us to // modify them (to override NULLs for example), and avoids an extra @@ -411,7 +411,12 @@ nni_ep_dial(nni_ep *ep, int flags) return (NNG_ECLOSED); } - if ((flags & NNG_FLAG_SYNCH) == 0) { + if (ep->ep_started) { + nni_mtx_unlock(&ep->ep_mtx); + return (NNG_ESTATE); + } + + if ((flags & NNG_FLAG_NONBLOCK) != 0) { nni_ep_con_start(ep); nni_mtx_unlock(&ep->ep_mtx); return (0); @@ -421,16 +426,18 @@ nni_ep_dial(nni_ep *ep, int flags) aio = &ep->ep_con_syn; aio->a_endpt = ep->ep_data; ep->ep_ops.ep_connect(ep->ep_data, aio); + ep->ep_started = 1; nni_mtx_unlock(&ep->ep_mtx); nni_aio_wait(aio); // As we're synchronous, we also have to handle the completion. - if ((rv = nni_aio_result(aio)) == 0) { - NNI_ASSERT(aio->a_pipe != NULL); - rv = nni_pipe_create(ep, aio->a_pipe); + if (((rv = nni_aio_result(aio)) != 0) || + ((rv = nni_pipe_create(ep, aio->a_pipe)) != 0)) { + nni_mtx_lock(&ep->ep_mtx); + ep->ep_started = 0; + nni_mtx_unlock(&ep->ep_mtx); } - return (rv); } @@ -503,14 +510,18 @@ nni_ep_listen(nni_ep *ep, int flags) nni_mtx_unlock(&ep->ep_mtx); return (NNG_ECLOSED); } + if (ep->ep_started) { + nni_mtx_unlock(&ep->ep_mtx); + return (NNG_ESTATE); + } rv = ep->ep_ops.ep_bind(ep->ep_data); if (rv != 0) { nni_mtx_unlock(&ep->ep_mtx); return (rv); } - ep->ep_bound = 1; + ep->ep_started = 1; nni_ep_acc_start(ep); nni_mtx_unlock(&ep->ep_mtx); @@ -278,18 +278,68 @@ nng_listen(nng_socket sid, const char *addr, nng_listener *lp, int flags) } int +nng_listener_create(nng_listener *lp, nng_socket sid, const char *addr) +{ + nni_sock *s; + nni_ep * ep; + int rv; + + if ((rv = nni_sock_find(&s, sid)) != 0) { + return (rv); + } + if ((rv = nni_ep_create_listener(&ep, s, addr)) != 0) { + nni_sock_rele(s); + return (rv); + } + *lp = nni_ep_id(ep); + nni_ep_rele(ep); + nni_sock_rele(s); + return (0); +} + +int +nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr) +{ + nni_sock *s; + nni_ep * ep; + int rv; + + if ((rv = nni_sock_find(&s, sid)) != 0) { + return (rv); + } + if ((rv = nni_ep_create_dialer(&ep, s, addr)) != 0) { + nni_sock_rele(s); + return (rv); + } + *dp = nni_ep_id(ep); + nni_ep_rele(ep); + nni_sock_rele(s); + return (0); +} + +static int +nng_ep_close(uint32_t id) +{ + nni_ep *ep; + int rv; + + if ((rv = nni_ep_find(&ep, id)) != 0) { + return (rv); + } + nni_ep_close(ep); + return (0); +} + +int nng_dialer_close(nng_dialer d) { - // return (nni_ep_close()); - NNI_ARG_UNUSED(d); - return (NNG_ENOTSUP); + return (nng_ep_close((uint32_t) d)); } int nng_listener_close(nng_listener l) { - NNI_ARG_UNUSED(l); - return (NNG_ENOTSUP); + return (nng_ep_close((uint32_t) l)); } int @@ -176,10 +176,10 @@ NNG_DECL int nng_listen(nng_socket, const char *, nng_listener *, int); NNG_DECL int nng_dial(nng_socket, const char *, nng_dialer *, int); // nng_dialer_create creates a new dialer, that is not yet started. -NNG_DECL int nng_dialer_create(nng_socket, const char *, nng_dialer *); +NNG_DECL int nng_dialer_create(nng_dialer *, nng_socket, const char *); // nng_listener_create creates a new listener, that is not yet started. -NNG_DECL int nng_listener_create(nng_socket, const char *, nng_listener *); +NNG_DECL int nng_listener_create(nng_listener *, nng_socket, const char *); // nng_dialer_start starts the endpoint dialing. This is only possible if // the dialer is not already dialing. @@ -301,8 +301,7 @@ NNG_DECL int nng_pipe_close(nng_pipe); // Flags. enum nng_flag_enum { NNG_FLAG_ALLOC = 1, // Recv to allocate receive buffer. - NNG_FLAG_NONBLOCK = 2, // Non-block send/recv. - NNG_FLAG_SYNCH = 4, // Synchronous dial / listen + NNG_FLAG_NONBLOCK = 2, // Non-blocking operations. }; // Protocol numbers. These are to be used with nng_socket_create(). diff --git a/src/nng_compat.c b/src/nng_compat.c index 48b406eb..bb0c9faa 100644 --- a/src/nng_compat.c +++ b/src/nng_compat.c @@ -162,7 +162,7 @@ nn_bind(int s, const char *addr) int rv; nng_listener l; - if ((rv = nng_listen((nng_socket) s, addr, &l, NNG_FLAG_SYNCH)) != 0) { + if ((rv = nng_listen((nng_socket) s, addr, &l, 0)) != 0) { nn_seterror(rv); return (-1); } @@ -175,7 +175,8 @@ nn_connect(int s, const char *addr) int rv; nng_dialer d; - if ((rv = nng_dial((nng_socket) s, addr, &d, 0)) != 0) { + if ((rv = nng_dial((nng_socket) s, addr, &d, NNG_FLAG_NONBLOCK)) != + 0) { nn_seterror(rv); return (-1); } diff --git a/src/transport/inproc/inproc.c b/src/transport/inproc/inproc.c index 37d7153f..3bc24c41 100644 --- a/src/transport/inproc/inproc.c +++ b/src/transport/inproc/inproc.c @@ -233,7 +233,6 @@ nni_inproc_ep_fini(void *arg) { nni_inproc_ep *ep = arg; - NNI_ASSERT(ep->closed); NNI_FREE_STRUCT(ep); } diff --git a/tests/bus.c b/tests/bus.c index e96a0a53..d242a7dd 100644 --- a/tests/bus.c +++ b/tests/bus.c @@ -8,7 +8,6 @@ // #include "convey.h" -#include "core/nng_impl.h" #include "nng.h" #include <string.h> @@ -18,89 +17,82 @@ So(nng_msg_len(m) == strlen(s)); \ So(memcmp(nng_msg_body(m), s, strlen(s)) == 0) -Main({ +TestMain("BUS pattern", { const char *addr = "inproc://test"; - atexit(nng_fini); + Reset({ nng_fini(); }); - Test("BUS pattern", { + Convey("We can create a BUS socket", { + nng_socket bus; - Convey("We can create a BUS socket", { - nng_socket bus; + So(nng_bus_open(&bus) == 0); - So(nng_bus_open(&bus) == 0); + Reset({ nng_close(bus); }); - Reset({ nng_close(bus); }); + Convey("Protocols match", { + So(nng_protocol(bus) == NNG_PROTO_BUS); + So(nng_peer(bus) == NNG_PROTO_BUS); + }); + }); + + Convey("We can create a linked BUS topology", { + nng_socket bus1; + nng_socket bus2; + nng_socket bus3; + uint64_t rtimeo; + + So(nng_bus_open(&bus1) == 0); + So(nng_bus_open(&bus2) == 0); + So(nng_bus_open(&bus3) == 0); - Convey("Protocols match", { - So(nng_protocol(bus) == NNG_PROTO_BUS); - So(nng_peer(bus) == NNG_PROTO_BUS); - }); + Reset({ + nng_close(bus1); + nng_close(bus2); + nng_close(bus3); }); - Convey("We can create a linked BUS topology", { - nng_socket bus1; - nng_socket bus2; - nng_socket bus3; - uint64_t rtimeo; - - So(nng_bus_open(&bus1) == 0); - So(nng_bus_open(&bus2) == 0); - So(nng_bus_open(&bus3) == 0); - - Reset({ - nng_close(bus1); - nng_close(bus2); - nng_close(bus3); - }); - - So(nng_listen(bus1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(bus2, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(bus3, addr, NULL, NNG_FLAG_SYNCH) == 0); - - rtimeo = 50000; - So(nng_setopt(bus1, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); - rtimeo = 50000; - So(nng_setopt(bus2, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); - rtimeo = 50000; - So(nng_setopt(bus3, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); - - Convey("Messages delivered", { - nng_msg *msg; - - // This is just a poor man's sleep. - So(nng_recvmsg(bus1, &msg, 0) == - NNG_ETIMEDOUT); - So(nng_recvmsg(bus2, &msg, 0) == - NNG_ETIMEDOUT); - So(nng_recvmsg(bus3, &msg, 0) == - NNG_ETIMEDOUT); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "99bits"); - So(nng_sendmsg(bus2, msg, 0) == 0); - - So(nng_recvmsg(bus1, &msg, 0) == 0); - CHECKSTR(msg, "99bits"); - nng_msg_free(msg); - So(nng_recvmsg(bus3, &msg, 0) == - NNG_ETIMEDOUT); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "onthe"); - So(nng_sendmsg(bus1, msg, 0) == 0); - - So(nng_recvmsg(bus2, &msg, 0) == 0); - CHECKSTR(msg, "onthe"); - nng_msg_free(msg); - - So(nng_recvmsg(bus3, &msg, 0) == 0); - CHECKSTR(msg, "onthe"); - nng_msg_free(msg); - }); + So(nng_listen(bus1, addr, NULL, 0) == 0); + So(nng_dial(bus2, addr, NULL, 0) == 0); + So(nng_dial(bus3, addr, NULL, 0) == 0); + + rtimeo = 50000; + So(nng_setopt( + bus1, NNG_OPT_RCVTIMEO, &rtimeo, sizeof(rtimeo)) == 0); + rtimeo = 50000; + So(nng_setopt( + bus2, NNG_OPT_RCVTIMEO, &rtimeo, sizeof(rtimeo)) == 0); + rtimeo = 50000; + So(nng_setopt( + bus3, NNG_OPT_RCVTIMEO, &rtimeo, sizeof(rtimeo)) == 0); + + Convey("Messages delivered", { + nng_msg *msg; + + // This is just a poor man's sleep. + So(nng_recvmsg(bus1, &msg, 0) == NNG_ETIMEDOUT); + So(nng_recvmsg(bus2, &msg, 0) == NNG_ETIMEDOUT); + So(nng_recvmsg(bus3, &msg, 0) == NNG_ETIMEDOUT); + + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "99bits"); + So(nng_sendmsg(bus2, msg, 0) == 0); + + So(nng_recvmsg(bus1, &msg, 0) == 0); + CHECKSTR(msg, "99bits"); + nng_msg_free(msg); + So(nng_recvmsg(bus3, &msg, 0) == NNG_ETIMEDOUT); + + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "onthe"); + So(nng_sendmsg(bus1, msg, 0) == 0); + + So(nng_recvmsg(bus2, &msg, 0) == 0); + CHECKSTR(msg, "onthe"); + nng_msg_free(msg); + + So(nng_recvmsg(bus3, &msg, 0) == 0); + CHECKSTR(msg, "onthe"); + nng_msg_free(msg); }); }); }) diff --git a/tests/device.c b/tests/device.c index ba0ebeca..85a06fca 100644 --- a/tests/device.c +++ b/tests/device.c @@ -67,14 +67,14 @@ Main({ nng_thread_destroy(thr); }); - So(nng_listen(dev1, addr1, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_listen(dev2, addr2, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(dev1, addr1, NULL, 0) == 0); + So(nng_listen(dev2, addr2, NULL, 0) == 0); So(nng_pair_open(&end1) == 0); So(nng_pair_open(&end2) == 0); - So(nng_dial(end1, addr1, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(end2, addr2, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(end1, addr1, NULL, 0) == 0); + So(nng_dial(end2, addr2, NULL, 0) == 0); tmo = 1000000; So(nng_setopt(end1, NNG_OPT_RCVTIMEO, &tmo, diff --git a/tests/event.c b/tests/event.c index d6fadc5a..8d7a969f 100644 --- a/tests/event.c +++ b/tests/event.c @@ -99,8 +99,8 @@ TestMain("Event Handling", { nng_close(sock2); }); - So(nng_listen(sock1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(sock2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(sock1, addr, NULL, 0) == 0); + So(nng_dial(sock2, addr, NULL, 0) == 0); // Let everything connect. nng_usleep(100000); diff --git a/tests/pair1.c b/tests/pair1.c index c5916e82..aa86883b 100644 --- a/tests/pair1.c +++ b/tests/pair1.c @@ -54,8 +54,8 @@ TestMain("PAIRv1 protocol", { Convey("Monogamous cooked mode works", { nng_msg *msg; - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); So(nng_msg_alloc(&msg, 0) == 0); APPENDSTR(msg, "ALPHA"); @@ -75,10 +75,10 @@ TestMain("PAIRv1 protocol", { Convey("Monogamous mode ignores new conns", { nng_msg *msg; - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); nng_usleep(100000); - So(nng_dial(c2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(c2, addr, NULL, 0) == 0); So(nng_msg_alloc(&msg, 0) == 0); APPENDSTR(msg, "ONE"); @@ -95,8 +95,8 @@ TestMain("PAIRv1 protocol", { Convey("Cannot set raw mode after connect", { int r = 1; - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); nng_usleep(100000); So(nng_setopt_int(s1, NNG_OPT_RAW, 1) == NNG_ESTATE); @@ -116,8 +116,8 @@ TestMain("PAIRv1 protocol", { So(nng_setopt_duration(s1, NNG_OPT_SNDTIMEO, 100000) == 0); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); for (i = 0, rv = 0; i < 10; i++) { So(nng_msg_alloc(&msg, 0) == 0); @@ -141,8 +141,8 @@ TestMain("PAIRv1 protocol", { So(nng_setopt_duration(s1, NNG_OPT_SNDTIMEO, 30000) == 0); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); // We choose to allow some buffering. In reality the // buffer size is just 1, and we will fail after 2. @@ -158,8 +158,8 @@ TestMain("PAIRv1 protocol", { }); Convey("Cannot set polyamorous mode after connect", { - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); nng_usleep(100000); So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == @@ -176,8 +176,8 @@ TestMain("PAIRv1 protocol", { So(nng_setopt_int(c1, NNG_OPT_RAW, 1) == 0); So(nng_setopt_int(c2, NNG_OPT_RAW, 1) == 0); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); Convey("Send/recv work", { So(nng_msg_alloc(&msg, 0) == 0); @@ -341,9 +341,9 @@ TestMain("PAIRv1 protocol", { So(nng_getopt_int(s1, NNG_OPT_POLYAMOROUS, &v) == 0); So(v == 1); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); + So(nng_dial(c2, addr, NULL, 0) == 0); So(nng_msg_alloc(&msg, 0) == 0); APPENDSTR(msg, "ONE"); @@ -396,10 +396,10 @@ TestMain("PAIRv1 protocol", { So(nng_setopt_int(s1, NNG_OPT_POLYAMOROUS, 1) == 0); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); nng_usleep(100000); - So(nng_dial(c2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(c2, addr, NULL, 0) == 0); So(nng_msg_alloc(&msg, 0) == 0); APPENDSTR(msg, "YES"); @@ -439,9 +439,9 @@ TestMain("PAIRv1 protocol", { So(nng_getopt_int(s1, NNG_OPT_RAW, &v) == 0); So(v == 1); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(c2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); + So(nng_dial(c1, addr, NULL, 0) == 0); + So(nng_dial(c2, addr, NULL, 0) == 0); Convey("Send/recv works", { So(nng_msg_alloc(&msg, 0) == 0); diff --git a/tests/pipeline.c b/tests/pipeline.c index e19faa9a..70b52350 100644 --- a/tests/pipeline.c +++ b/tests/pipeline.c @@ -75,9 +75,9 @@ Main({ // Its important to avoid a startup race that the // sender be the dialer. Otherwise you need a delay // since the server accept is really asynchronous. - So(nng_listen(pull, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(push, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(what, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(pull, addr, NULL, 0) == 0); + So(nng_dial(push, addr, NULL, 0) == 0); + So(nng_dial(what, addr, NULL, 0) == 0); So(nng_shutdown(what) == 0); Convey("Push can send messages, and pull can recv", { @@ -152,10 +152,10 @@ Main({ sizeof(usecs)) == 0); So(nng_setopt(pull3, NNG_OPT_RCVTIMEO, &usecs, sizeof(usecs)) == 0); - So(nng_listen(push, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(pull1, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(pull2, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(pull3, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(push, addr, NULL, 0) == 0); + So(nng_dial(pull1, addr, NULL, 0) == 0); + So(nng_dial(pull2, addr, NULL, 0) == 0); + So(nng_dial(pull3, addr, NULL, 0) == 0); So(nng_shutdown(pull3) == 0); // So pull3 might not be done accepting yet, but pull1 diff --git a/tests/pubsub.c b/tests/pubsub.c index 19d85848..2712181d 100644 --- a/tests/pubsub.c +++ b/tests/pubsub.c @@ -9,7 +9,6 @@ // #include "convey.h" -#include "core/nng_impl.h" #include "nng.h" #include <string.h> @@ -19,161 +18,155 @@ So(nng_msg_len(m) == strlen(s)); \ So(memcmp(nng_msg_body(m), s, strlen(s)) == 0) -Main({ +TestMain("PUB/SUB pattern", { const char *addr = "inproc://test"; - nni_init(); - Test("PUB/SUB pattern", { - Convey("We can create a PUB socket", { - nng_socket pub; + Reset({ nng_fini(); }); - So(nng_pub_open(&pub) == 0); + Convey("We can create a PUB socket", { + nng_socket pub; - Reset({ nng_close(pub); }); + So(nng_pub_open(&pub) == 0); - Convey("Protocols match", { - So(nng_protocol(pub) == NNG_PROTO_PUB); - So(nng_peer(pub) == NNG_PROTO_SUB); - }); + Reset({ nng_close(pub); }); - Convey("Recv fails", { - nng_msg *msg; - So(nng_recvmsg(pub, &msg, 0) == NNG_ENOTSUP); - }); + Convey("Protocols match", { + So(nng_protocol(pub) == NNG_PROTO_PUB); + So(nng_peer(pub) == NNG_PROTO_SUB); }); - Convey("We can create a SUB socket", { - nng_socket sub; - So(nng_sub_open(&sub) == 0); + Convey("Recv fails", { + nng_msg *msg; + So(nng_recvmsg(pub, &msg, 0) == NNG_ENOTSUP); + }); + }); - Reset({ nng_close(sub); }); + Convey("We can create a SUB socket", { + nng_socket sub; + So(nng_sub_open(&sub) == 0); - Convey("Protocols match", { - So(nng_protocol(sub) == NNG_PROTO_SUB); - So(nng_peer(sub) == NNG_PROTO_PUB); - }); + Reset({ nng_close(sub); }); - Convey("Send fails", { - nng_msg *msg; - So(nng_msg_alloc(&msg, 0) == 0); - So(nng_sendmsg(sub, msg, 0) == NNG_ENOTSUP); - nng_msg_free(msg); - }); + Convey("Protocols match", { + So(nng_protocol(sub) == NNG_PROTO_SUB); + So(nng_peer(sub) == NNG_PROTO_PUB); }); - Convey("We can create a linked PUB/SUB pair", { - nng_socket pub; - nng_socket sub; + Convey("Send fails", { + nng_msg *msg; + So(nng_msg_alloc(&msg, 0) == 0); + So(nng_sendmsg(sub, msg, 0) == NNG_ENOTSUP); + nng_msg_free(msg); + }); + }); - So(nng_pub_open(&pub) == 0); + Convey("We can create a linked PUB/SUB pair", { + nng_socket pub; + nng_socket sub; - So(nng_sub_open(&sub) == 0); + So(nng_pub_open(&pub) == 0); - Reset({ - nng_close(pub); - nng_close(sub); - }); + So(nng_sub_open(&sub) == 0); + + Reset({ + nng_close(pub); + nng_close(sub); + }); - // Most consumers will usually have the pub - // listen, and the sub dial. However, this - // creates a problem for our tests, since we - // can wind up trying to push data before the - // pipe is fully registered (the accept runs in - // an asynch thread.) Doing the reverse here - // ensures that we won't lose data. - So(nng_listen(sub, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(pub, addr, NULL, NNG_FLAG_SYNCH) == 0); - - Convey("Sub can subscribe", { + // Most applications will usually have the pub listen, + // and the sub dial. However, this creates a problem + // for our tests, since we can wind up trying to push + // data before the pipe is fully registered (the accept + // runs asynchronously.) Doing the reverse here + // ensures that we won't lose data. + So(nng_listen(sub, addr, NULL, 0) == 0); + So(nng_dial(pub, addr, NULL, 0) == 0); + + Convey("Sub can subscribe", { + So(nng_setopt(sub, NNG_OPT_SUBSCRIBE, "ABC", 3) == 0); + So(nng_setopt(sub, NNG_OPT_SUBSCRIBE, "", 0) == 0); + Convey("Unsubscribe works", { + So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, "ABC", + 3) == 0); So(nng_setopt( - sub, NNG_OPT_SUBSCRIBE, "ABC", 3) == 0); - So(nng_setopt(sub, NNG_OPT_SUBSCRIBE, "", 0) == - 0); - Convey("Unsubscribe works", { - So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, - "ABC", 3) == 0); - So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, - "", 0) == 0); - - So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, - "", 0) == NNG_ENOENT); - So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, - "HELLO", 0) == NNG_ENOENT); - }); - }); + sub, NNG_OPT_UNSUBSCRIBE, "", 0) == 0); - Convey("Pub cannot subscribe", { - So(nng_setopt(pub, NNG_OPT_SUBSCRIBE, "", 0) == - NNG_ENOTSUP); + So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, "", + 0) == NNG_ENOENT); + So(nng_setopt(sub, NNG_OPT_UNSUBSCRIBE, + "HELLO", 0) == NNG_ENOENT); }); + }); - Convey("Subs can receive from pubs", { - nng_msg *msg; - uint64_t rtimeo; - - So(nng_setopt(sub, NNG_OPT_SUBSCRIBE, "/some/", - strlen("/some/")) == 0); - rtimeo = 50000; // 50ms - So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "/some/like/it/hot"); - So(nng_sendmsg(pub, msg, 0) == 0); - So(nng_recvmsg(sub, &msg, 0) == 0); - CHECKSTR(msg, "/some/like/it/hot"); - nng_msg_free(msg); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "/somewhere/over/the/rainbow"); - CHECKSTR(msg, "/somewhere/over/the/rainbow"); - - So(nng_sendmsg(pub, msg, 0) == 0); - So(nng_recvmsg(sub, &msg, 0) == NNG_ETIMEDOUT); - - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "/some/day/some/how"); - CHECKSTR(msg, "/some/day/some/how"); - - So(nng_sendmsg(pub, msg, 0) == 0); - So(nng_recvmsg(sub, &msg, 0) == 0); - CHECKSTR(msg, "/some/day/some/how"); - nng_msg_free(msg); - }); + Convey("Pub cannot subscribe", { + So(nng_setopt(pub, NNG_OPT_SUBSCRIBE, "", 0) == + NNG_ENOTSUP); + }); + + Convey("Subs can receive from pubs", { + nng_msg *msg; + uint64_t rtimeo; + + So(nng_setopt(sub, NNG_OPT_SUBSCRIBE, "/some/", + strlen("/some/")) == 0); + rtimeo = 50000; // 50ms + So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, + sizeof(rtimeo)) == 0); + + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "/some/like/it/hot"); + So(nng_sendmsg(pub, msg, 0) == 0); + So(nng_recvmsg(sub, &msg, 0) == 0); + CHECKSTR(msg, "/some/like/it/hot"); + nng_msg_free(msg); + + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "/somewhere/over/the/rainbow"); + CHECKSTR(msg, "/somewhere/over/the/rainbow"); + + So(nng_sendmsg(pub, msg, 0) == 0); + So(nng_recvmsg(sub, &msg, 0) == NNG_ETIMEDOUT); + + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "/some/day/some/how"); + CHECKSTR(msg, "/some/day/some/how"); + + So(nng_sendmsg(pub, msg, 0) == 0); + So(nng_recvmsg(sub, &msg, 0) == 0); + CHECKSTR(msg, "/some/day/some/how"); + nng_msg_free(msg); + }); - Convey("Subs without subsciptions don't receive", { + Convey("Subs without subsciptions don't receive", { - uint64_t rtimeo = 50000; // 50ms - nng_msg *msg; - So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); + uint64_t rtimeo = 50000; // 50ms + nng_msg *msg; + So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, + sizeof(rtimeo)) == 0); - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "/some/don't/like/it"); - So(nng_sendmsg(pub, msg, 0) == 0); - So(nng_recvmsg(sub, &msg, 0) == NNG_ETIMEDOUT); - }); + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "/some/don't/like/it"); + So(nng_sendmsg(pub, msg, 0) == 0); + So(nng_recvmsg(sub, &msg, 0) == NNG_ETIMEDOUT); + }); - Convey("Subs in raw receive", { + Convey("Subs in raw receive", { - uint64_t rtimeo = 50000; // 500ms - int raw = 1; - nng_msg *msg; + uint64_t rtimeo = 50000; // 500ms + int raw = 1; + nng_msg *msg; - So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, - sizeof(rtimeo)) == 0); - So(nng_setopt(sub, NNG_OPT_RAW, &raw, - sizeof(raw)) == 0); + So(nng_setopt(sub, NNG_OPT_RCVTIMEO, &rtimeo, + sizeof(rtimeo)) == 0); + So(nng_setopt(sub, NNG_OPT_RAW, &raw, sizeof(raw)) == + 0); - So(nng_msg_alloc(&msg, 0) == 0); - APPENDSTR(msg, "/some/like/it/raw"); - So(nng_sendmsg(pub, msg, 0) == 0); - So(nng_recvmsg(sub, &msg, 0) == 0); - CHECKSTR(msg, "/some/like/it/raw"); - nng_msg_free(msg); - }); + So(nng_msg_alloc(&msg, 0) == 0); + APPENDSTR(msg, "/some/like/it/raw"); + So(nng_sendmsg(pub, msg, 0) == 0); + So(nng_recvmsg(sub, &msg, 0) == 0); + CHECKSTR(msg, "/some/like/it/raw"); + nng_msg_free(msg); }); }); - - nni_fini(); }) diff --git a/tests/reqrep.c b/tests/reqrep.c index 447060b0..b27af5ac 100644 --- a/tests/reqrep.c +++ b/tests/reqrep.c @@ -68,8 +68,8 @@ TestMain("REQ/REP pattern", { nng_close(req); }); - So(nng_listen(rep, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(req, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(rep, addr, NULL, 0) == 0); + So(nng_dial(req, addr, NULL, 0) == 0); Convey("They can REQ/REP exchange", { nng_msg *ping; @@ -123,7 +123,7 @@ TestMain("REQ/REP pattern", { So(nng_msg_alloc(&def, 0) == 0); So(nng_msg_append(def, "def", 4) == 0); - So(nng_listen(rep, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(rep, addr, NULL, 0) == 0); So(nng_dial(req, addr, NULL, 0) == 0); So(nng_sendmsg(req, abc, 0) == 0); diff --git a/tests/scalability.c b/tests/scalability.c index e9422f8e..a7347343 100644 --- a/tests/scalability.c +++ b/tests/scalability.c @@ -61,7 +61,7 @@ openclients(nng_socket *clients, int num) "setopt(SNDTIMEO) #%d: %s\n", i, nng_strerror(rv)); return (rv); } - rv = nng_dial(clients[i], addr, NULL, NNG_FLAG_SYNCH); + rv = nng_dial(clients[i], addr, NULL, 0); if (rv != 0) { printf("dial #%d: %s\n", i, nng_strerror(rv)); return (rv); @@ -123,7 +123,7 @@ Main({ if ((nng_rep_open(&rep) != 0) || (nng_setopt(rep, NNG_OPT_RCVBUF, &depth, sizeof(depth)) != 0) || (nng_setopt(rep, NNG_OPT_SNDBUF, &depth, sizeof(depth)) != 0) || - (nng_listen(rep, addr, NULL, NNG_FLAG_SYNCH) != 0) || + (nng_listen(rep, addr, NULL, 0) != 0) || (nng_thread_create(&server, serve, &rep) != 0)) { fprintf(stderr, "Unable to set up server!\n"); exit(1); diff --git a/tests/sock.c b/tests/sock.c index 56159aae..31d48333 100644 --- a/tests/sock.c +++ b/tests/sock.c @@ -25,8 +25,27 @@ TestMain("Socket Operations", { Reset({ nng_close(s1); }); Convey("And we can shut it down", { + char * buf; + size_t sz; So(nng_shutdown(s1) == 0); So(nng_shutdown(s1) == NNG_ECLOSED); + Convey("It can't receive", { + So(nng_recv(s1, &buf, &sz, NNG_FLAG_ALLOC) == + NNG_ECLOSED); + }); + Convey("It can't send", + { So(nng_send(s1, "", 0, 0) == NNG_ECLOSED); }); + Convey("Cannot create endpoints", { + nng_dialer d; + nng_listener l; + char * a = "inproc://closed"; + So(nng_dialer_create(&d, s1, a) == + NNG_ECLOSED); + So(nng_listener_create(&l, s1, a) == + NNG_ECLOSED); + So(nng_dial(s1, a, &d, 0) == NNG_ECLOSED); + So(nng_listen(s1, a, &l, 0) == NNG_ECLOSED); + }); }); Convey("It's type & peer are still PAIR", { @@ -176,17 +195,37 @@ TestMain("Socket Operations", { }); Convey("Dialing synch can get refused", { - rv = nng_dial(s1, "inproc://no", NULL, NNG_FLAG_SYNCH); + rv = nng_dial(s1, "inproc://no", NULL, 0); So(rv == NNG_ECONNREFUSED); }); + Convey("Dialing asynch does not get refused", { + char * buf; + size_t sz; + nng_socket s2; + char * a = "inproc://asy"; + So(nng_dial(s1, a, NULL, NNG_FLAG_NONBLOCK) == 0); + Convey("And connects late", { + So(nng_pair_open(&s2) == 0); + Reset({ nng_close(s2); }); + So(nng_listen(s2, a, NULL, 0) == 0); + nng_usleep(100000); + So(nng_send(s1, "abc", 4, 0) == 0); + So(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) == + 0); + So(sz == 4); + So(memcmp(buf, "abc", 4) == 0); + nng_free(buf, sz); + }); + }); + Convey("Listening works", { char *a = "inproc://here"; - rv = nng_listen(s1, a, NULL, NNG_FLAG_SYNCH); + rv = nng_listen(s1, a, NULL, 0); So(rv == 0); Convey("Second listen fails ADDRINUSE", { - rv = nng_listen(s1, a, NULL, NNG_FLAG_SYNCH); + rv = nng_listen(s1, a, NULL, 0); So(rv == NNG_EADDRINUSE); }); @@ -194,7 +233,7 @@ TestMain("Socket Operations", { nng_socket s2; So(nng_pair_open(&s2) == 0); Reset({ nng_close(s2); }); - So(nng_dial(s2, a, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(s2, a, NULL, 0) == 0); nng_close(s2); }); }); @@ -222,8 +261,8 @@ TestMain("Socket Operations", { So(nng_setopt_duration(s2, NNG_OPT_SNDTIMEO, to) == 0); So(nng_setopt_duration(s2, NNG_OPT_RCVTIMEO, to) == 0); - So(nng_listen(s1, a, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial(s2, a, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, a, NULL, 0) == 0); + So(nng_dial(s2, a, NULL, 0) == 0); So(nng_send(s1, "abc", 4, 0) == 0); So(nng_recv(s2, &buf, &sz, NNG_FLAG_ALLOC) == 0); diff --git a/tests/survey.c b/tests/survey.c index 2a757a98..2bdd2930 100644 --- a/tests/survey.c +++ b/tests/survey.c @@ -99,18 +99,15 @@ Main({ So(nng_setopt(surv, NNG_OPT_SURVEYTIME, &expire, sizeof(expire)) == 0); - So(nng_listen( - surv, addr, NULL, NNG_FLAG_SYNCH) == 0); - So(nng_dial( - resp, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(surv, addr, NULL, 0) == 0); + So(nng_dial(resp, addr, NULL, 0) == 0); // We dial another socket as that will force // the earlier dial to have completed *fully*. // This is a hack that only works because our // listen logic is single threaded. So(nng_respondent_open(&sock) == 0); - So(nng_dial( - sock, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(sock, addr, NULL, 0) == 0); nng_close(sock); Convey("Survey works", { diff --git a/tests/tcp.c b/tests/tcp.c index 58c9bca7..324c167e 100644 --- a/tests/tcp.c +++ b/tests/tcp.c @@ -24,7 +24,7 @@ TestMain("TCP Transport", { So(nng_pair_open(&s) == 0); Reset({ nng_close(s); }); trantest_next_address(addr, "tcp://*:%u"); - So(nng_dial(s, addr, NULL, NNG_FLAG_SYNCH) == NNG_EADDRINVAL); + So(nng_dial(s, addr, NULL, 0) == NNG_EADDRINVAL); }); Convey("We can bind to wild card", { @@ -39,10 +39,10 @@ TestMain("TCP Transport", { nng_close(s1); }); trantest_next_address(addr, "tcp://*:%u"); - So(nng_listen(s1, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_listen(s1, addr, NULL, 0) == 0); // reset port back one trantest_prev_address(addr, "tcp://127.0.0.1:%u"); - So(nng_dial(s2, addr, NULL, NNG_FLAG_SYNCH) == 0); + So(nng_dial(s2, addr, NULL, 0) == 0); }); nng_fini(); diff --git a/tests/trantest.h b/tests/trantest.h index 639d0632..84b54e34 100644 --- a/tests/trantest.h +++ b/tests/trantest.h @@ -84,11 +84,9 @@ trantest_conn_refused(trantest *tt) Convey("Connection refused works", { nng_dialer d = 0; - So(nng_dial(tt->reqsock, tt->addr, &d, NNG_FLAG_SYNCH) == - NNG_ECONNREFUSED); + So(nng_dial(tt->reqsock, tt->addr, &d, 0) == NNG_ECONNREFUSED); So(d == 0); - So(nng_dial(tt->repsock, tt->addr, &d, NNG_FLAG_SYNCH) == - NNG_ECONNREFUSED); + So(nng_dial(tt->repsock, tt->addr, &d, 0) == NNG_ECONNREFUSED); So(d == 0); }) } @@ -98,11 +96,10 @@ trantest_duplicate_listen(trantest *tt) { Convey("Duplicate listen rejected", { nng_listener l; - So(nng_listen(tt->repsock, tt->addr, &l, NNG_FLAG_SYNCH) == 0); + So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0); So(l != 0); l = 0; - So(nng_listen(tt->reqsock, tt->addr, &l, NNG_FLAG_SYNCH) == - NNG_EADDRINUSE); + So(nng_listen(tt->reqsock, tt->addr, &l, 0) == NNG_EADDRINUSE); So(l == 0); }) } @@ -113,11 +110,11 @@ trantest_listen_accept(trantest *tt) Convey("Listen and accept", { nng_listener l; nng_dialer d; - So(nng_listen(tt->repsock, tt->addr, &l, NNG_FLAG_SYNCH) == 0); + So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0); So(l != 0); d = 0; - So(nng_dial(tt->reqsock, tt->addr, &d, NNG_FLAG_SYNCH) == 0); + So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0); So(d != 0); }) } @@ -132,9 +129,9 @@ trantest_send_recv(trantest *tt) nng_msg * recv; size_t len; - So(nng_listen(tt->repsock, tt->addr, &l, NNG_FLAG_SYNCH) == 0); + So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0); So(l != 0); - So(nng_dial(tt->reqsock, tt->addr, &d, NNG_FLAG_SYNCH) == 0); + So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0); So(d != 0); send = NULL; |
