From 67eb45ce0ea5beeab41d25e7d059118ca9828f3d Mon Sep 17 00:00:00 2001
From: Steven McCoy <steven.mccoy@miru.hk>
Date: Mon, 8 Aug 2011 14:59:04 +0800
Subject: [PATCH 4/4] Add support to tcp_connector for ipv4only flag.


Signed-off-by: Steven McCoy <steven.mccoy@miru.hk>
---
 src/tcp_connecter.cpp |   62 ++++++++++++++++++++++++++++++++++---------------
 src/tcp_connecter.hpp |    2 +-
 src/zmq_connecter.cpp |    2 +-
 3 files changed, 45 insertions(+), 21 deletions(-)

diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp
index 883293e..d150220 100644
--- a/src/tcp_connecter.cpp
+++ b/src/tcp_connecter.cpp
@@ -42,10 +42,12 @@ zmq::tcp_connecter_t::~tcp_connecter_t ()
         close ();
 }
 
-int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_)
+int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_,
+    bool ipv4only_)
 {
-    if (strcmp (protocol_, "tcp") == 0)
-        return resolve_ip_hostname (&addr, &addr_len, addr_, true);
+    if (strcmp (protocol_, "tcp") == 0) {
+        return resolve_ip_hostname (&addr, &addr_len, addr_, ipv4only_);
+    }
 
     errno = EPROTONOSUPPORT;
     return -1;    
@@ -62,15 +64,27 @@ int zmq::tcp_connecter_t::open ()
         return -1;
     }
 
+    int rc;
+    DWORD flag;
+    //  Enable IPv4-mapping of addresses in IPv6 on Windows Vista and later.
+#ifdef IPV6_V6ONLY
+    if (addr.ss_family == AF_INET6) {
+        flag = 0;
+        rc = setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
+            (const char*) &flag, sizeof (flag));
+        wsa_assert (rc != SOCKET_ERROR);
+    }
+#endif
+
     // Set to non-blocking mode.
     unsigned long argp = 1;
-    int rc = ioctlsocket (s, FIONBIO, &argp);
+    rc = ioctlsocket (s, FIONBIO, &argp);
     wsa_assert (rc != SOCKET_ERROR);
 
     //  Disable Nagle's algorithm.
-    int flag = 1;
+    flag = 1;
     rc = setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
-        sizeof (int));
+        sizeof (flag));
     wsa_assert (rc != SOCKET_ERROR);
 
     //  Connect to the remote peer.
@@ -156,10 +170,11 @@ zmq::tcp_connecter_t::~tcp_connecter_t ()
         close ();
 }
 
-int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_)
+int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_,
+    bool ipv4only_)
 {
     if (strcmp (protocol_, "tcp") == 0)
-        return resolve_ip_hostname (&addr, &addr_len, addr_, true);
+        return resolve_ip_hostname (&addr, &addr_len, addr_, ipv4only_);
     else if (strcmp (protocol_, "ipc") == 0)
         return resolve_local_path (&addr, &addr_len, addr_);
 
@@ -179,21 +194,30 @@ int zmq::tcp_connecter_t::open ()
         if (s == -1)
             return -1;
 
+        int rc;
+        int flag;
+        //  Enable IPv4-mapping of addresses in IPv6 on Windows Vista and later.
+        if (addr.ss_family == AF_INET6) {
+            flag = 0;
+            rc = setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
+                (const char*) &flag, sizeof (flag));
+            errno_assert (rc == 0);
+        }
         // Set to non-blocking mode.
 #ifdef ZMQ_HAVE_OPENVMS
-    	int flags = 1;
-    	int rc = ioctl (s, FIONBIO, &flags);
+    	int argp = 1;
+    	rc = ioctl (s, FIONBIO, &argp);
         errno_assert (rc != -1);
 #else
-    	int flags = fcntl (s, F_GETFL, 0);
-    	if (flags == -1)
-            flags = 0;
-    	int rc = fcntl (s, F_SETFL, flags | O_NONBLOCK);
+    	int argp = fcntl (s, F_GETFL, 0);
+    	if (argp == -1)
+            argp = 0;
+    	rc = fcntl (s, F_SETFL, argp | O_NONBLOCK);
         errno_assert (rc != -1);
 #endif
 
         //  Disable Nagle's algorithm.
-        int flag = 1;
+        flag = 1;
         rc = setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
             sizeof (int));
         errno_assert (rc == 0);
@@ -236,10 +260,10 @@ int zmq::tcp_connecter_t::open ()
             return -1;
 
         //  Set the non-blocking flag.
-        int flag = fcntl (s, F_GETFL, 0);
-        if (flag == -1) 
-            flag = 0;
-        int rc = fcntl (s, F_SETFL, flag | O_NONBLOCK);
+        int argp = fcntl (s, F_GETFL, 0);
+        if (argp == -1) 
+            argp = 0;
+        int rc = fcntl (s, F_SETFL, argp | O_NONBLOCK);
         errno_assert (rc != -1);
 
         //  Connect to the remote peer.
diff --git a/src/tcp_connecter.hpp b/src/tcp_connecter.hpp
index 06641e5..b9f241d 100644
--- a/src/tcp_connecter.hpp
+++ b/src/tcp_connecter.hpp
@@ -44,7 +44,7 @@ namespace zmq
         ~tcp_connecter_t ();
 
         //  Set address to connect to.
-        int set_address (const char *protocol, const char *addr_);
+        int set_address (const char *protocol, const char *addr_, bool ipv4only_);
 
         //  Open TCP connecting socket. Address is in
         //  <hostname>:<port-number> format. Returns -1 in case of error,
diff --git a/src/zmq_connecter.cpp b/src/zmq_connecter.cpp
index ca9bb77..8779b01 100644
--- a/src/zmq_connecter.cpp
+++ b/src/zmq_connecter.cpp
@@ -44,7 +44,7 @@ zmq::zmq_connecter_t::zmq_connecter_t (class io_thread_t *io_thread_,
     session (session_),
     current_reconnect_ivl(options.reconnect_ivl)
 {
-    int rc = tcp_connecter.set_address (protocol_, address_);
+    int rc = tcp_connecter.set_address (protocol_, address_, true);
     zmq_assert (rc == 0); //TODO: take care ENOMEM, EINVAL
 }
 
-- 
1.7.4.1

