Hi.

I've made a patch for binding a source address as was proposed by fredrik danerklint in thread 'Bind to local ip address' lately.

It works as:
zmq_connect(s, "tcp://source;endpoint:port");

source is optional. Interface name should work but it does not (at least for me on FreeBSD). But it's not a porblem of the patch, it's a point for another patch.
>From 4b0f204b591a4a4a2c0b4707e84bf62c055bd48d Mon Sep 17 00:00:00 2001
From: Sergey Matveychuk <[email protected]>
Date: Sat, 17 Dec 2011 16:00:33 +0400
Subject: [PATCH] Allow to set up a source address for outgoing connections in
 zmq_connect() Signed-off-by: Sergey Matveychuk
 <[email protected]>

---
 doc/zmq_tcp.txt       |    7 ++++---
 src/tcp_address.cpp   |   35 +++++++++++++++++++----------------
 src/tcp_address.hpp   |    2 +-
 src/tcp_connecter.cpp |   18 +++++++++++++++++-
 src/tcp_connecter.hpp |    3 +++
 5 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/doc/zmq_tcp.txt b/doc/zmq_tcp.txt
index a6d7be3..739e0d3 100644
--- a/doc/zmq_tcp.txt
+++ b/doc/zmq_tcp.txt
@@ -17,9 +17,10 @@ your first choice.
 ADDRESSING
 ----------
 A 0MQ 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 de6e0ad..d8d21d6 100644
--- a/src/tcp_address.cpp
+++ b/src/tcp_address.cpp
@@ -369,31 +369,34 @@ zmq::tcp_address_t::~tcp_address_t ()
 {
 }
 
-int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv4only_)
+int zmq::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;
-    }
-
-    //  Separate the address/port.
-    std::string addr_str (name_, delimiter - name_);
-    std::string port_str (delimiter + 1);
+    std::string addr_str;
+    uint16_t port = 0;
+
+    if (!ignore_port_) {
+	if (!delimiter) {
+	    errno = EINVAL;
+	    return -1;
+	}
+	//  Separate the address/port.
+	addr_str = std::string (name_, delimiter - name_);
+	//  Parse the port number (0 is not a valid port).
+	uint16_t 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 d4768c7..5e97b50 100644
--- a/src/tcp_address.hpp
+++ b/src/tcp_address.hpp
@@ -45,7 +45,7 @@ namespace zmq
         //  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 ZMQ_HAVE_WINDOWS
         unsigned short family ();
diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp
index 042e82a..9ac10d6 100644
--- a/src/tcp_connecter.cpp
+++ b/src/tcp_connecter.cpp
@@ -178,7 +178,19 @@ int zmq::tcp_connecter_t::get_new_reconnect_ivl ()
 
 int zmq::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_, ';');
+    int ret = 0;
+    std::string addr_str;
+
+    if (delimiter) {
+	std::string saddr_str (addr_, delimiter - addr_);
+	addr_str = delimiter + 1;
+	ret = source_address.resolve (saddr_str.c_str(), true, options.ipv4only ? true : false, true);
+    } else
+	addr_str = addr_;
+
+    return ret || address.resolve (addr_str.c_str(), false, options.ipv4only ? true : false);
 }
 
 int zmq::tcp_connecter_t::open ()
@@ -205,6 +217,10 @@ int zmq::tcp_connecter_t::open ()
     // 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 fc3b9f2..9404296 100644
--- a/src/tcp_connecter.hpp
+++ b/src/tcp_connecter.hpp
@@ -87,6 +87,9 @@ namespace zmq
         //  Address to connect to.
         tcp_address_t address;
 
+	// Source address
+	tcp_address_t source_address;
+
         //  Underlying socket.
         fd_t s;
 
-- 
1.7.7.3

_______________________________________________
zeromq-dev mailing list
[email protected]
http://lists.zeromq.org/mailman/listinfo/zeromq-dev

Reply via email to