diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-05-22 10:27:47 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-05-22 10:29:06 -0700 |
| commit | 959eabe2675a3b8be9bc2b2459cc899a5a64b283 (patch) | |
| tree | 373fba9ab3c7cf4c769efb1c42f896694bf16d25 | |
| parent | 67f5ed6e5c0dd7bdd9002bbb519ab34f35fef8dd (diff) | |
| download | nng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.tar.gz nng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.tar.bz2 nng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.zip | |
fixes #474 websocket listen on ws://*:<x> fails
fixes #464 Support NN_WS_MSG_TYPE option (compat)
fixes #415 websocket does not honor recv maxsize
This fixes a significant (and security) issue in websocket, where the
code does not honor a maximum receive size. We've exposed new API
(internal) to set the limit on the frame size, and we've changed the
default to *unlimited* for that internal API. (But the default for SP
sockets, which are the only consumers at present, is still 1MB just like
all other SP transports.)
| -rw-r--r-- | src/compat/nanomsg/nn.c | 33 | ||||
| -rw-r--r-- | src/core/url.c | 6 | ||||
| -rw-r--r-- | src/supplemental/http/http_server.c | 35 | ||||
| -rw-r--r-- | src/supplemental/websocket/websocket.c | 46 | ||||
| -rw-r--r-- | src/supplemental/websocket/websocket.h | 6 | ||||
| -rw-r--r-- | src/transport/ws/websocket.c | 8 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/compat_ws.c | 281 |
8 files changed, 385 insertions, 31 deletions
diff --git a/src/compat/nanomsg/nn.c b/src/compat/nanomsg/nn.c index 564e60d8..bc27832e 100644 --- a/src/compat/nanomsg/nn.c +++ b/src/compat/nanomsg/nn.c @@ -749,6 +749,33 @@ nn_setignore(nng_socket s, const void *valp, size_t sz) } static int +nn_getwsmsgtype(nng_socket s, void *valp, size_t *szp) +{ + int val = NN_WS_MSG_TYPE_BINARY; + NNI_ARG_UNUSED(s); + memcpy(valp, &val, *szp < sizeof(val) ? *szp : sizeof(val)); + *szp = sizeof(val); + return (0); +} + +static int +nn_setwsmsgtype(nng_socket s, const void *valp, size_t sz) +{ + int val; + NNI_ARG_UNUSED(s); + if (sz != sizeof(val)) { + nn_seterror(NNG_EINVAL); + return (-1); + } + memcpy(&val, valp, sizeof(val)); + if (val != NN_WS_MSG_TYPE_BINARY) { + nn_seterror(NNG_EINVAL); + return (-1); + } + return (0); +} + +static int nn_settcpnodelay(nng_socket s, const void *valp, size_t sz) { bool val; @@ -1039,6 +1066,12 @@ static const struct { .nnopt = NN_TCP_NODELAY, .get = nn_gettcpnodelay, .set = nn_settcpnodelay, + }, + { + .nnlevel = NN_WS, + .nnopt = NN_WS_MSG_TYPE, + .get = nn_getwsmsgtype, + .set = nn_setwsmsgtype, } // XXX: IPV4ONLY, SNDPRIO, RCVPRIO }; diff --git a/src/core/url.c b/src/core/url.c index 93f1298e..7d45f82d 100644 --- a/src/core/url.c +++ b/src/core/url.c @@ -421,6 +421,12 @@ nni_url_parse(nni_url **urlp, const char *raw) s++; // skip over ']', only used with IPv6 addresses } if (s[0] == ':') { + // If a colon was present, but no port value present, then + // that is an error. + if (s[1] == '\0') { + rv = NNG_EINVAL; + goto error; + } url->u_port = nni_strdup(s + 1); } else { url->u_port = nni_strdup(nni_url_default_port(url->u_scheme)); diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index c7738aee..5c6d1dcc 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -30,7 +30,7 @@ static nni_initializer http_server_initializer = { struct nng_http_handler { nni_list_node node; - char * path; + char * uri; char * method; char * host; bool tree; @@ -75,14 +75,18 @@ struct nng_http_server { int nni_http_handler_init( - nni_http_handler **hp, const char *path, void (*cb)(nni_aio *)) + nni_http_handler **hp, const char *uri, void (*cb)(nni_aio *)) { nni_http_handler *h; if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { return (NNG_ENOMEM); } - if (((h->path = nni_strdup(path)) == NULL) || + // Default for HTTP is /. + if ((uri == NULL) || (strlen(uri) == 0)) { + uri = "/"; + } + if (((h->uri = nni_strdup(uri)) == NULL) || ((h->method = nni_strdup("GET")) == NULL)) { nni_http_handler_fini(h); return (NNG_ENOMEM); @@ -108,7 +112,7 @@ nni_http_handler_fini(nni_http_handler *h) h->dtor(h->data); } nni_strfree(h->host); - nni_strfree(h->path); + nni_strfree(h->uri); nni_strfree(h->method); NNI_FREE_STRUCT(h); } @@ -133,7 +137,7 @@ nni_http_handler_get_data(nni_http_handler *h) const char * nni_http_handler_get_uri(nni_http_handler *h) { - return (h->path); + return (h->uri); } int @@ -383,8 +387,7 @@ http_uri_canonify(char *path) } *dst = '\0'; - // XXX: this is where we should also remove /./ and /../ references. - return (path); + return ((strlen(path) != 0) ? path : "/"); } static void @@ -527,8 +530,8 @@ http_sconn_rxdone(void *arg) } } - len = strlen(h->path); - if (strncmp(path, h->path, len) != 0) { + len = strlen(h->uri); + if (strncmp(path, h->uri, len) != 0) { continue; } switch (path[len]) { @@ -957,11 +960,11 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) // Must have a legal method (and not one that is HEAD), path, // and handler. (The reason HEAD is verboten is that we supply // it automatically as part of GET support.) - if (((len = strlen(h->path)) == 0) || (h->path[0] != '/') || + if (((len = strlen(h->uri)) == 0) || (h->uri[0] != '/') || (h->cb == NULL)) { return (NNG_EINVAL); } - while ((len > 0) && (h->path[len - 1] == '/')) { + while ((len > 0) && (h->uri[len - 1] == '/')) { len--; // ignore trailing '/' (this collapses them) } @@ -992,22 +995,22 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) continue; } - len2 = strlen(h2->path); + len2 = strlen(h2->uri); - while ((len2 > 0) && (h2->path[len2 - 1] == '/')) { + while ((len2 > 0) && (h2->uri[len2 - 1] == '/')) { len2--; // ignore trailing '/' } - if (strncmp(h->path, h2->path, len > len2 ? len2 : len) != 0) { + if (strncmp(h->uri, h2->uri, len > len2 ? len2 : len) != 0) { continue; // prefixes don't match. } if (len2 > len) { - if ((h2->path[len] == '/') && (h->tree)) { + if ((h2->uri[len] == '/') && (h->tree)) { nni_mtx_unlock(&s->mtx); return (NNG_EADDRINUSE); } } else if (len > len2) { - if ((h->path[len2] == '/') && (h2->tree)) { + if ((h->uri[len2] == '/') && (h2->tree)) { nni_mtx_unlock(&s->mtx); return (NNG_EADDRINUSE); } diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index 6d4d3c13..18491190 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -75,6 +75,7 @@ struct nni_ws_listener { nni_ws_listen_hook hookfn; void * hookarg; nni_list headers; // response headers + size_t maxframe; }; // The dialer tracks user aios in two lists. The first list is for aios @@ -94,6 +95,7 @@ struct nni_ws_dialer { bool closed; nng_sockaddr sa; nni_list headers; // request headers + size_t maxframe; }; typedef enum ws_type { @@ -945,7 +947,7 @@ ws_read_cb(void *arg) break; } - if (frame->len > ws->maxframe) { + if ((frame->len > ws->maxframe) && (ws->maxframe > 0)) { ws_close(ws, WS_CLOSE_TOO_BIG); nni_mtx_unlock(&ws->mtx); return; @@ -1380,7 +1382,6 @@ ws_init(nni_ws **wsp) nni_aio_set_timeout(ws->httpaio, 2000); ws->fragsize = 1 << 20; // we won't send a frame larger than this - ws->maxframe = (1 << 20) * 10; // default limit on incoming frame size *wsp = ws; return (0); } @@ -1557,12 +1558,13 @@ ws_handler(nni_aio *aio) status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; goto err; } - ws->http = conn; - ws->req = req; - ws->res = res; - ws->mode = NNI_EP_MODE_LISTEN; + ws->http = conn; + ws->req = req; + ws->res = res; + ws->mode = NNI_EP_MODE_LISTEN; + ws->maxframe = l->maxframe; - // XXX: Inherit fragmentation and message size limits! + // XXX: Inherit fragmentation? (Frag is limited for now). nni_list_append(&l->reply, ws); nni_aio_set_data(ws->httpaio, 0, l); @@ -1621,7 +1623,8 @@ nni_ws_listener_init(nni_ws_listener **wslp, nni_url *url) return (rv); } - *wslp = l; + l->maxframe = 0; + *wslp = l; return (0); } @@ -1785,6 +1788,14 @@ nni_ws_listener_get_tls(nni_ws_listener *l, nng_tls_config **tlsp) } void +nni_ws_listener_set_maxframe(nni_ws_listener *l, size_t maxframe) +{ + nni_mtx_lock(&l->mtx); + l->maxframe = maxframe; + nni_mtx_unlock(&l->mtx); +} + +void ws_conn_cb(void *arg) { nni_ws_dialer *d; @@ -1920,8 +1931,8 @@ nni_ws_dialer_init(nni_ws_dialer **dp, nni_url *url) nni_ws_dialer_fini(d); return (rv); } - - *dp = d; + d->maxframe = 0; + *dp = d; return (0); } @@ -2021,9 +2032,10 @@ nni_ws_dialer_dial(nni_ws_dialer *d, nni_aio *aio) ws_fini(ws); return; } - ws->dialer = d; - ws->useraio = aio; - ws->mode = NNI_EP_MODE_DIAL; + ws->dialer = d; + ws->useraio = aio; + ws->mode = NNI_EP_MODE_DIAL; + ws->maxframe = d->maxframe; nni_list_append(&d->wspend, ws); nni_http_client_connect(d->client, ws->connaio); nni_mtx_unlock(&d->mtx); @@ -2071,6 +2083,14 @@ nni_ws_dialer_header(nni_ws_dialer *d, const char *n, const char *v) return (rv); } +void +nni_ws_dialer_set_maxframe(nni_ws_dialer *d, size_t maxframe) +{ + nni_mtx_lock(&d->mtx); + d->maxframe = maxframe; + nni_mtx_unlock(&d->mtx); +} + // Dialer does not get a hook chance, as it can examine the request // and reply after dial is done; this is not a 3-way handshake, so // the dialer does not confirm the server's response at the HTTP diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h index 546f41a9..9936b10f 100644 --- a/src/supplemental/websocket/websocket.h +++ b/src/supplemental/websocket/websocket.h @@ -33,14 +33,16 @@ extern int nni_ws_listener_listen(nni_ws_listener *); extern void nni_ws_listener_accept(nni_ws_listener *, nng_aio *); extern void nni_ws_listener_hook( nni_ws_listener *, nni_ws_listen_hook, void *); -extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *); -extern int nni_ws_listener_get_tls(nni_ws_listener *, nng_tls_config **s); +extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *); +extern int nni_ws_listener_get_tls(nni_ws_listener *, nng_tls_config **s); +extern void nni_ws_listener_set_maxframe(nni_ws_listener *, size_t); extern int nni_ws_dialer_init(nni_ws_dialer **, nni_url *); extern void nni_ws_dialer_fini(nni_ws_dialer *); extern void nni_ws_dialer_close(nni_ws_dialer *); extern int nni_ws_dialer_proto(nni_ws_dialer *, const char *); extern int nni_ws_dialer_header(nni_ws_dialer *, const char *, const char *); +extern void nni_ws_dialer_set_maxframe(nni_ws_dialer *, size_t); extern void nni_ws_dialer_dial(nni_ws_dialer *, nng_aio *); extern int nni_ws_dialer_set_tls(nni_ws_dialer *, nng_tls_config *); extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **); diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c index 36deddac..97175d49 100644 --- a/src/transport/ws/websocket.c +++ b/src/transport/ws/websocket.c @@ -284,7 +284,9 @@ ws_ep_bind(void *arg) ws_ep *ep = arg; int rv; + nni_ws_listener_set_maxframe(ep->listener, ep->rcvmax); nni_ws_listener_hook(ep->listener, ws_hook, ep); + if ((rv = nni_ws_listener_listen(ep->listener)) == 0) { ep->started = true; } @@ -359,6 +361,7 @@ ws_ep_connect(void *arg, nni_aio *aio) NNI_ASSERT(nni_list_empty(&ep->aios)); ep->started = true; nni_list_append(&ep->aios, aio); + nni_ws_dialer_set_maxframe(ep->dialer, ep->rcvmax); nni_ws_dialer_dial(ep->dialer, ep->connaio); nni_mtx_unlock(&ep->mtx); } @@ -373,6 +376,11 @@ ws_ep_setopt_recvmaxsz(void *arg, const void *v, size_t sz, int typ) rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, typ); if ((rv == 0) && (ep != NULL)) { ep->rcvmax = val; + if (ep->mode == NNI_EP_MODE_DIAL) { + nni_ws_dialer_set_maxframe(ep->dialer, ep->rcvmax); + } else { + nni_ws_listener_set_maxframe(ep->listener, ep->rcvmax); + } } return (rv); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6a8d5e86..e7d751ac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -197,6 +197,7 @@ add_nng_compat_test(compat_reqttl 5) add_nng_compat_test(compat_shutdown 5) add_nng_compat_test(compat_surveyttl 5) add_nng_compat_test(compat_tcp 60) +add_nng_compat_test(compat_ws 60) # These are special tests for compat mode, not inherited from the # legacy libnanomsg suite. diff --git a/tests/compat_ws.c b/tests/compat_ws.c new file mode 100644 index 00000000..6d019364 --- /dev/null +++ b/tests/compat_ws.c @@ -0,0 +1,281 @@ +/* + Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> + Copyright 2018 Capitar IT Group BV <info@capitar.com> + Copyright (c) 2012 250bpm s.r.o. All rights reserved. + Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. + Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.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. +*/ + +// This file began life in nanomsg, but we have made some significant changes +// to it. Specifically, NNG has no support for text frames, requires that +// maximum receive frame sizes be set before connections are established, +// has support for IPv6, and does not support local interface binding. +// We have improved the maximum receive size test, and verified that option +// setting for the frame type conforms to NNG constraints. + +#include <nanomsg/nn.h> +#include <nanomsg/pair.h> +#include <nanomsg/ws.h> + +#include "compat_testutil.h" + +static char socket_address[128]; + +/* Basic tests for WebSocket transport. */ + +#if 0 // NNG has no support for text frames. +/* test_text() verifies that we drop messages properly when sending invalid + UTF-8, but not when we send valid data. */ +void test_text () +{ + int sb; + int sc; + int opt; + uint8_t bad[20]; + + /* Negative testing... bad UTF-8 data for text. */ + sb = test_socket (AF_SP, NN_PAIR); + sc = test_socket (AF_SP, NN_PAIR); + + opt = NN_WS_MSG_TYPE_TEXT; + test_setsockopt (sb, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); + + opt = NN_WS_MSG_TYPE_TEXT; + test_setsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); + opt = 500; + test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt)); + + test_bind (sb, socket_address); + test_connect (sc, socket_address); + + test_send (sc, "GOOD"); + test_recv (sb, "GOOD"); + + /* and the bad ... */ + strcpy ((char *)bad, "BAD."); + bad[2] = (char)0xDD; + test_send (sc, (char *)bad); + + /* Make sure we dropped the frame. */ + test_drop (sb, ETIMEDOUT); + + test_close (sb); + test_close (sc); + + return; +} +#endif + +int main (int argc, const char *argv[]) +{ + int rc; + int sb; + int sc; + int sb2; + int opt; + size_t sz; + int i; + char any_address[128]; + + test_addr_from (socket_address, "ws", "127.0.0.1", + get_test_port (argc, argv)); + + test_addr_from (any_address, "ws", "*", + get_test_port (argc, argv)); + + /* Try closing bound but unconnected socket. */ + sb = test_socket (AF_SP, NN_PAIR); + test_bind (sb, any_address); + test_close (sb); + + /* Try closing a TCP socket while it not connected. At the same time + test specifying the local address for the connection. */ + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, socket_address); + test_close (sc); + + /* Open the socket anew. */ + sc = test_socket (AF_SP, NN_PAIR); + + /* Check socket options. */ + sz = sizeof (opt); + rc = nn_getsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, &sz); + errno_assert (rc == 0); + nn_assert (sz == sizeof (opt)); + nn_assert (opt == NN_WS_MSG_TYPE_BINARY); + + /* Default port 80 should be assumed if not explicitly declared. */ + rc = nn_connect (sc, "ws://127.0.0.1"); + errno_assert (rc >= 0); + + /* Try using invalid address strings. */ + rc = nn_connect (sc, "ws://*:"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://*:1000000"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://*:some_port"); + nn_assert (rc < 0); +#if 0 // NNG doesn't support device binding + rc = nn_connect (sc, "ws://eth10000;127.0.0.1:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == ENODEV); +#endif + + rc = nn_bind (sc, "ws://127.0.0.1:"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_bind (sc, "ws://127.0.0.1:1000000"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); +#if 0 // NNG doesn't support device binding + rc = nn_bind (sc, "ws://eth10000:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == ENODEV); +#endif + + rc = nn_connect (sc, "ws://:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://-hostname:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://abc.123.---.#:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); +#if 0 // Nothing wrong with this under NNG. Valid IPv6 URL + rc = nn_connect (sc, "ws://[::1]:5555"); + nn_assert (rc < 0); +#endif + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://abc...123:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + rc = nn_connect (sc, "ws://.123:5555"); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + + test_close (sc); + + 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(100); + /* Ping-pong test. */ + for (i = 0; i != 100; ++i) { + + test_send (sc, "ABC"); + test_recv (sb, "ABC"); + + test_send (sb, "DEF"); + test_recv (sc, "DEF"); + } + + /* Batch transfer test. */ + for (i = 0; i != 100; ++i) { + test_send (sc, "0123456789012345678901234567890123456789"); + } + for (i = 0; i != 100; ++i) { + test_recv (sb, "0123456789012345678901234567890123456789"); + } + + test_close (sc); + test_close (sb); + + /* Test two sockets binding to the same address. */ + sb = test_socket (AF_SP, NN_PAIR); + test_bind (sb, socket_address); + sb2 = test_socket (AF_SP, NN_PAIR); + + rc = nn_bind (sb2, socket_address); + nn_assert (rc < 0); + errno_assert (nn_errno () == EADDRINUSE); + test_close(sb); + test_close(sb2); + + /* Test that NN_RCVMAXSIZE can be -1, but not lower */ + sb = test_socket (AF_SP, NN_PAIR); + opt = -1; + rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); + nn_assert (rc >= 0); + opt = -2; + rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + test_close (sb); + + /* Test NN_RCVMAXSIZE limit */ + sb = test_socket (AF_SP, NN_PAIR); + opt = 4; + test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); + test_bind (sb, socket_address); + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, socket_address); + opt = 1000; + test_setsockopt (sc, NN_SOL_SOCKET, NN_SNDTIMEO, &opt, sizeof (opt)); + nn_assert (opt == 1000); + opt = 1000; + test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt)); + nn_assert (opt == 1000); + test_send (sc, "ABC"); + test_recv (sb, "ABC"); + test_send (sc, "ABCD"); + test_recv (sb, "ABCD"); + test_send (sc, "ABCDE"); + test_drop (sb, ETIMEDOUT); + test_close (sc); + + /* Increase the size limit, reconnect, then try sending again. */ + opt = 5; + test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); + + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, socket_address); + nn_sleep(200); + + test_send (sc, "ABCDE"); + test_recv (sb, "ABCDE"); + test_close (sb); + test_close (sc); + +#if 0 // NNG doesn't support text frames. + test_text (); +#else + opt = NN_WS_MSG_TYPE_TEXT; + rc = nn_setsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); + nn_assert (rc < 0); + errno_assert (nn_errno () == EINVAL); + + opt = NN_WS_MSG_TYPE_BINARY; + test_setsockopt (sb, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); +#endif + + /* Test closing a socket that is waiting to connect. */ + sc = test_socket (AF_SP, NN_PAIR); + test_connect (sc, socket_address); + nn_sleep (100); + test_close (sc); + + return 0; +} |
