summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--doc/xs_tcp.txt7
-rw-r--r--src/tcp_address.cpp42
-rw-r--r--src/tcp_address.hpp3
-rw-r--r--src/tcp_connecter.cpp24
-rw-r--r--src/tcp_connecter.hpp3
6 files changed, 55 insertions, 25 deletions
diff --git a/AUTHORS b/AUTHORS
index 258a25d..c5ec023 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -66,6 +66,7 @@ Pieter Hintjens <ph@imatix.com>
Piotr Trojanek <piotr.trojanek@gmail.com>
Robert G. Jakabosky <bobby@sharedrealm.com>
Sebastian Otaegui <feniix@gmail.com>
+Sergey Matveychuk <sem33@yandex-team.ru>
Staffan Gimåker <staffan@spotify.com>
Steven McCoy <steven.mccoy@miru.hk>
Stuart Webster <sw_webster@hotmail.com>
diff --git a/doc/xs_tcp.txt b/doc/xs_tcp.txt
index 5d5cbca..b97be08 100644
--- a/doc/xs_tcp.txt
+++ b/doc/xs_tcp.txt
@@ -17,9 +17,10 @@ be your first choice.
ADDRESSING
----------
A Crossroads address string consists of two parts as follows:
-'transport'`://`'endpoint'. The 'transport' part specifies the underlying
-transport protocol to use, and for the TCP transport shall be set to `tcp`.
-The meaning of the 'endpoint' part for the TCP transport is defined below.
+'transport'`://[`'source address'`;]`'endpoint'. The 'transport' part specifies
+the underlying transport protocol to use, and for the TCP transport shall be
+set to `tcp`. 'source address' is optional. The meaning of the 'endpoint' part
+for the TCP transport is defined below.
Assigning a local address to a socket
diff --git a/src/tcp_address.cpp b/src/tcp_address.cpp
index 3b6ed94..11f3793 100644
--- a/src/tcp_address.cpp
+++ b/src/tcp_address.cpp
@@ -250,11 +250,8 @@ int xs::tcp_address_t::resolve_interface (char const *interface_,
int rc = resolve_nic_name (interface_, ipv4only_);
if (rc != 0 && errno != ENODEV)
return rc;
- if (rc == 0) {
- xs_assert (out_addrlen <= (socklen_t) sizeof (address));
- memcpy (&address, out_addr, out_addrlen);
+ if (rc == 0)
return 0;
- }
// There's no such interface name. Assume literal address.
#if defined XS_HAVE_OPENVMS && defined __ia64
@@ -369,31 +366,38 @@ xs::tcp_address_t::~tcp_address_t ()
{
}
-int xs::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
+int xs::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_,
+ bool ignore_port_)
{
// Find the ':' at end that separates address from the port number.
const char *delimiter = strrchr (name_, ':');
- if (!delimiter) {
- errno = EINVAL;
- return -1;
- }
+ std::string addr_str;
+ uint16_t port = 0;
+
+ if (!ignore_port_) {
+ if (!delimiter) {
+ errno = EINVAL;
+ return -1;
+ }
- // Separate the address/port.
- std::string addr_str (name_, delimiter - name_);
- std::string port_str (delimiter + 1);
+ // Separate the address/port.
+ addr_str = std::string (name_, delimiter - name_);
+
+ // Parse the port number (0 is not a valid port).
+ port = (uint16_t) atoi (delimiter+1);
+ if (port == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ else
+ addr_str = name_;
// Remove square brackets around the address, if any.
if (!addr_str.empty () && addr_str [0] == '[' &&
addr_str [addr_str.size () - 1] == ']')
addr_str = addr_str.substr (1, addr_str.size () - 2);
- // Parse the port number (0 is not a valid port).
- uint16_t port = (uint16_t) atoi (port_str.c_str());
- if (port == 0) {
- errno = EINVAL;
- return -1;
- }
-
// Resolve the IP address.
int rc;
if (local_)
diff --git a/src/tcp_address.hpp b/src/tcp_address.hpp
index 683f30f..4730cd7 100644
--- a/src/tcp_address.hpp
+++ b/src/tcp_address.hpp
@@ -45,7 +45,8 @@ namespace xs
// strcuture. If 'local' is true, names are resolved as local interface
// names. If it is false, names are resolved as remote hostnames.
// If 'ipv4only' is true, the name will never resolve to IPv6 address.
- int resolve (const char* name_, bool local_, bool ipv4only_);
+ int resolve (const char* name_, bool local_, bool ipv4only_,
+ bool ignore_port_=false);
#if defined XS_HAVE_WINDOWS
unsigned short family ();
diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp
index 2844a3b..36ddfa7 100644
--- a/src/tcp_connecter.cpp
+++ b/src/tcp_connecter.cpp
@@ -178,7 +178,23 @@ int xs::tcp_connecter_t::get_new_reconnect_ivl ()
int xs::tcp_connecter_t::set_address (const char *addr_)
{
- return address.resolve (addr_, false, options.ipv4only ? true : false);
+ // Find the ';'. It separates source address address from a destination.
+ const char *delimiter = strchr (addr_, ';');
+
+ std::string addr_str;
+ if (delimiter) {
+ std::string saddr_str (addr_, delimiter - addr_);
+ addr_str = delimiter + 1;
+ int rc = source_address.resolve (saddr_str.c_str(), true,
+ options.ipv4only ? true : false, true);
+ if (rc != 0)
+ return -1;
+ }
+ else
+ addr_str = addr_;
+
+ return address.resolve (addr_str.c_str(), false,
+ options.ipv4only ? true : false);
}
int xs::tcp_connecter_t::open ()
@@ -202,9 +218,13 @@ int xs::tcp_connecter_t::open ()
if (address.family () == AF_INET6)
enable_ipv4_mapping (s);
- // Set the socket to non-blocking mode so that we get async connect().
+ // Set the socket to non-blocking mode so that we get async connect().
unblock_socket (s);
+ // Set a source address for conversations.
+ if (source_address.family ())
+ ::bind (s, source_address.addr (), source_address.addrlen ());
+
// Connect to the remote peer.
int rc = ::connect (s, address.addr (), address.addrlen ());
diff --git a/src/tcp_connecter.hpp b/src/tcp_connecter.hpp
index dcc909d..a174473 100644
--- a/src/tcp_connecter.hpp
+++ b/src/tcp_connecter.hpp
@@ -87,6 +87,9 @@ namespace xs
// Address to connect to.
tcp_address_t address;
+ // Source address.
+ tcp_address_t source_address;
+
// Underlying socket.
fd_t s;