diff options
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | doc/xs_tcp.txt | 7 | ||||
| -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 | 
6 files changed, 55 insertions, 25 deletions
@@ -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;  | 
