aboutsummaryrefslogtreecommitdiff
path: root/src/platform/posix
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-08-19 08:07:02 -0700
committerGarrett D'Amore <garrett@damore.org>2018-08-27 08:00:23 -0700
commit83b7a9afec7b3659974c614cea69fa3abb904d24 (patch)
tree7277bda8deb32c91614f236fb942a4c6cfbbe55b /src/platform/posix
parent1c3350f6f4a738815c39a67dc0ba1a953a1b9f03 (diff)
downloadnng-83b7a9afec7b3659974c614cea69fa3abb904d24.tar.gz
nng-83b7a9afec7b3659974c614cea69fa3abb904d24.tar.bz2
nng-83b7a9afec7b3659974c614cea69fa3abb904d24.zip
fixes #608 Add TCP support to specify local network interface
This also fixes a leaked TCP connection on a failure path, which we noticed while working this change.
Diffstat (limited to 'src/platform/posix')
-rw-r--r--src/platform/posix/posix_tcp.h8
-rw-r--r--src/platform/posix/posix_tcpdial.c46
2 files changed, 51 insertions, 3 deletions
diff --git a/src/platform/posix/posix_tcp.h b/src/platform/posix/posix_tcp.h
index aefce7f7..633a63b5 100644
--- a/src/platform/posix/posix_tcp.h
+++ b/src/platform/posix/posix_tcp.h
@@ -25,9 +25,11 @@ struct nni_tcp_conn {
};
struct nni_tcp_dialer {
- nni_list connq; // pending connections
- bool closed;
- nni_mtx mtx;
+ nni_list connq; // pending connections
+ bool closed;
+ struct sockaddr_storage src;
+ size_t srclen;
+ nni_mtx mtx;
};
struct nni_tcp_listener {
diff --git a/src/platform/posix/posix_tcpdial.c b/src/platform/posix/posix_tcpdial.c
index ab3f3545..918ee9ba 100644
--- a/src/platform/posix/posix_tcpdial.c
+++ b/src/platform/posix/posix_tcpdial.c
@@ -149,6 +149,46 @@ tcp_dialer_cb(nni_posix_pfd *pfd, int ev, void *arg)
nni_aio_finish(aio, 0, 0);
}
+int
+nni_tcp_dialer_set_src_addr(nni_tcp_dialer *d, const nni_sockaddr *sa)
+{
+ struct sockaddr_storage ss;
+ struct sockaddr_in * sin;
+ struct sockaddr_in6 * sin6;
+ size_t sslen;
+
+ if ((sslen = nni_posix_nn2sockaddr(&ss, sa)) == 0) {
+ return (NNG_EADDRINVAL);
+ }
+ // Ensure we are either IPv4 or IPv6, and port is not set. (We
+ // do not allow binding to a specific port.)
+ switch (ss.ss_family) {
+ case AF_INET:
+ sin = (void *) &ss;
+ if (sin->sin_port != 0) {
+ return (NNG_EADDRINVAL);
+ }
+ break;
+ case AF_INET6:
+ sin6 = (void *) &ss;
+ if (sin6->sin6_port != 0) {
+ return (NNG_EADDRINVAL);
+ }
+ break;
+ default:
+ return (NNG_EADDRINVAL);
+ }
+ nni_mtx_lock(&d->mtx);
+ if (d->closed) {
+ nni_mtx_unlock(&d->mtx);
+ return (NNG_ECLOSED);
+ }
+ d->src = ss;
+ d->srclen = sslen;
+ nni_mtx_unlock(&d->mtx);
+ return (0);
+}
+
// We don't give local address binding support. Outbound dialers always
// get an ephemeral port.
void
@@ -196,6 +236,12 @@ nni_tcp_dialer_dial(nni_tcp_dialer *d, const nni_sockaddr *sa, nni_aio *aio)
rv = NNG_ECLOSED;
goto error;
}
+ if (d->srclen != 0) {
+ if ((rv = bind(fd, (void *) &d->src, d->srclen)) != 0) {
+ rv = nni_plat_errno(errno);
+ goto error;
+ }
+ }
if ((rv = nni_aio_schedule(aio, tcp_dialer_cancel, d)) != 0) {
goto error;
}