aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-05-21 15:51:08 -0700
committerGarrett D'Amore <garrett@damore.org>2018-05-21 21:27:16 -0700
commitd0cf8ce6f43daf6882037dbdcdaa7f2169dd1e6a (patch)
treeb6201f5f27c556b0a8102669605220fffccd4528 /src
parent45692d50c33f1fbc45554a5b82281046c4b3621a (diff)
downloadnng-d0cf8ce6f43daf6882037dbdcdaa7f2169dd1e6a.tar.gz
nng-d0cf8ce6f43daf6882037dbdcdaa7f2169dd1e6a.tar.bz2
nng-d0cf8ce6f43daf6882037dbdcdaa7f2169dd1e6a.zip
fixes #469 SO_REUSEADDR should be enabled
fixes #468 TCP nodelay and keepalive should start usable fixes #467 NN_RCVMAXSZ option does not work (compat) fixes #465 Support NN_OPT_TCPNODELAY (compat) This is a rather larger change set than I'd like, but when adding support for legacy TCP keepalive, I found a number if issues using the legacy TCP test (which we are introducing with this commit.) This fixes the concerns that are relevant and addressible. We have elected not to try to support to local address binding at this time, and the IPv6 test case in the old code was wrong, so changes relevant to that are commented out. I've also updated the nng_compat manual page to reflect additional caveats that folks should be aware of, including the previously undocumented caveat around the NN_SNDBUF and NN_RCVBUF options.
Diffstat (limited to 'src')
-rw-r--r--src/compat/nanomsg/nn.c120
-rw-r--r--src/core/socket.c11
-rw-r--r--src/platform/posix/posix_epdesc.c10
3 files changed, 137 insertions, 4 deletions
diff --git a/src/compat/nanomsg/nn.c b/src/compat/nanomsg/nn.c
index 6755a8ea..564e60d8 100644
--- a/src/compat/nanomsg/nn.c
+++ b/src/compat/nanomsg/nn.c
@@ -64,7 +64,7 @@ static const struct {
{ NNG_ENOENT, ENOENT },
{ NNG_EPROTO, EPROTO },
{ NNG_EUNREACHABLE, EHOSTUNREACH },
- { NNG_EADDRINVAL, EADDRNOTAVAIL },
+ { NNG_EADDRINVAL, EINVAL },
{ NNG_EPERM, EACCES },
{ NNG_EMSGSIZE, EMSGSIZE },
{ NNG_ECONNABORTED, ECONNABORTED },
@@ -237,6 +237,8 @@ nn_socket(int domain, int protocol)
return (-1);
}
+ // Legacy sockets have nodelay disabled.
+ (void) nng_setopt_bool(sock, NNG_OPT_TCP_NODELAY, false);
return ((int) sock.id);
}
@@ -747,6 +749,54 @@ nn_setignore(nng_socket s, const void *valp, size_t sz)
}
static int
+nn_settcpnodelay(nng_socket s, const void *valp, size_t sz)
+{
+ bool val;
+ int ival;
+ int rv;
+
+ if (sz != sizeof(ival)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(&ival, valp, sizeof(ival));
+ switch (ival) {
+ case 0:
+ val = false;
+ break;
+ case 1:
+ val = true;
+ break;
+ default:
+ nn_seterror(NNG_EINVAL);
+ return (-1);
+ }
+
+ if ((rv = nng_setopt_bool(s, NNG_OPT_TCP_NODELAY, val)) != 0) {
+ nn_seterror(rv);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+nn_gettcpnodelay(nng_socket s, void *valp, size_t *szp)
+{
+ bool val;
+ int ival;
+ int rv;
+
+ if ((rv = nng_getopt_bool(s, NNG_OPT_TCP_NODELAY, &val)) != 0) {
+ nn_seterror(rv);
+ return (-1);
+ }
+ ival = val ? 1 : 0;
+ memcpy(valp, &ival, *szp < sizeof(ival) ? *szp : sizeof(ival));
+ *szp = sizeof(ival);
+ return (0);
+}
+
+static int
nn_getrcvbuf(nng_socket s, void *valp, size_t *szp)
{
int cnt;
@@ -769,7 +819,7 @@ nn_setrcvbuf(nng_socket s, const void *valp, size_t sz)
int rv;
if (sz != sizeof(cnt)) {
- nn_seterror(NNG_EINVAL);
+ errno = EINVAL;
return (-1);
}
memcpy(&cnt, valp, sizeof(cnt));
@@ -808,7 +858,7 @@ nn_setsndbuf(nng_socket s, const void *valp, size_t sz)
int rv;
if (sz != sizeof(cnt)) {
- nn_seterror(NNG_EINVAL);
+ errno = EINVAL;
return (-1);
}
memcpy(&cnt, valp, sizeof(cnt));
@@ -824,6 +874,61 @@ nn_setsndbuf(nng_socket s, const void *valp, size_t sz)
return (0);
}
+static int
+nn_setrcvmaxsz(nng_socket s, const void *valp, size_t sz)
+{
+ int ival;
+ size_t val;
+ int rv;
+
+ if (sz != sizeof(ival)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(&ival, valp, sizeof(ival));
+ if (ival == -1) {
+ val = 0;
+ } else if (ival >= 0) {
+ // Note that if the user sets 0, it disables the limit.
+ // This is a different semantic.
+ val = (size_t) ival;
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((rv = nng_setopt_size(s, NNG_OPT_RECVMAXSZ, val)) != 0) {
+ nn_seterror(rv);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+nn_getrcvmaxsz(nng_socket s, void *valp, size_t *szp)
+{
+ int ival;
+ int rv;
+ size_t val;
+
+ if ((rv = nng_getopt_size(s, NNG_OPT_RECVMAXSZ, &val)) != 0) {
+ nn_seterror(rv);
+ return (-1);
+ }
+ // Legacy uses -1 to mean unlimited. New code uses 0. Note that
+ // as a consequence, we can't set a message limit of zero.
+ // We report any size beyond 2GB as effectively unlimited.
+ // There is an implicit assumption here that ints are 32-bits,
+ // but that's generally true of any platform we support.
+ if ((val == 0) || (val > 0x7FFFFFFF)) {
+ ival = -1;
+ } else {
+ ival = (int) val;
+ }
+ memcpy(valp, &ival, *szp < sizeof(ival) ? *szp : sizeof(ival));
+ *szp = sizeof(ival);
+ return (0);
+}
+
// options which we convert -- most of the array is initialized at run time.
static const struct {
int nnlevel;
@@ -881,7 +986,8 @@ static const struct {
{
.nnlevel = NN_SOL_SOCKET,
.nnopt = NN_RCVMAXSIZE,
- .opt = NNG_OPT_RECVMAXSZ,
+ .get = nn_getrcvmaxsz,
+ .set = nn_setrcvmaxsz,
},
{
.nnlevel = NN_SOL_SOCKET,
@@ -928,6 +1034,12 @@ static const struct {
.nnopt = NN_SURVEYOR_DEADLINE,
.opt = NNG_OPT_SURVEYOR_SURVEYTIME,
},
+ {
+ .nnlevel = NN_TCP,
+ .nnopt = NN_TCP_NODELAY,
+ .get = nn_gettcpnodelay,
+ .set = nn_settcpnodelay,
+ }
// XXX: IPV4ONLY, SNDPRIO, RCVPRIO
};
diff --git a/src/core/socket.c b/src/core/socket.c
index 3a209441..faca1b06 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -532,6 +532,7 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto)
{
int rv;
nni_sock *s;
+ bool on;
if ((s = NNI_ALLOC_STRUCT(s)) == NULL) {
return (NNG_ENOMEM);
@@ -587,6 +588,16 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto)
return (rv);
}
+ // These we *attempt* to call so that we are likely to have initial
+ // values loaded. They should not fail, but if they do we don't
+ // worry about it.
+ on = true;
+ (void) nni_sock_setopt(
+ s, NNG_OPT_TCP_NODELAY, &on, sizeof(on), NNI_TYPE_BOOL);
+ on = false;
+ (void) nni_sock_setopt(
+ s, NNG_OPT_TCP_KEEPALIVE, &on, sizeof(on), NNI_TYPE_BOOL);
+
if (s->s_sock_ops.sock_filter != NULL) {
nni_msgq_set_filter(
s->s_urq, s->s_sock_ops.sock_filter, s->s_data);
diff --git a/src/platform/posix/posix_epdesc.c b/src/platform/posix/posix_epdesc.c
index 0065806d..dfb750d4 100644
--- a/src/platform/posix/posix_epdesc.c
+++ b/src/platform/posix/posix_epdesc.c
@@ -247,6 +247,16 @@ nni_posix_epdesc_listen(nni_posix_epdesc *ed)
return (rv);
}
+#if defined(SO_REUSEADDR) && !defined(NNG_PLATFORM_WSL)
+ if (ss->ss_family != AF_UNIX) {
+ int on = 1;
+ // If for some reason this doesn't work, it's probably ok.
+ // Second bind will fail.
+ (void) setsockopt(
+ fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ }
+#endif
+
if (bind(fd, (struct sockaddr *) ss, len) < 0) {
rv = nni_plat_errno(errno);
nni_mtx_unlock(&ed->mtx);