diff options
author | Sergey Matveychuk <sem33@yandex-team.ru> | 2012-02-16 10:03:02 +0900 |
---|---|---|
committer | Martin Sustrik <sustrik@250bpm.com> | 2012-02-16 10:03:02 +0900 |
commit | f9f25ccc2b4a365edc00d922a2aa056cca7fe861 (patch) | |
tree | 5fb03cec4eab12a7cdc8623f38aaba563320b034 /src | |
parent | c71e11bed498926efdcdf022bc560a350e45251c (diff) |
Allow to set up a source address for outgoing connections in zmq_connect()
Signed-off-by: Sergey Matveychuk <sem33@yandex-team.ru>
Signed-off-by: Martin Sustrik <sustik@250bpm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/tcp_address.cpp | 42 | ||||
-rw-r--r-- | src/tcp_address.hpp | 3 | ||||
-rw-r--r-- | src/tcp_connecter.cpp | 24 | ||||
-rw-r--r-- | src/tcp_connecter.hpp | 3 |
4 files changed, 50 insertions, 22 deletions
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; |