Skip to content

Commit

Permalink
Merge d80d9cc into 7fd082b
Browse files Browse the repository at this point in the history
  • Loading branch information
fbacchella committed Feb 27, 2019
2 parents 7fd082b + d80d9cc commit 0c987cc
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 68 deletions.
13 changes: 9 additions & 4 deletions src/main/java/org/zeromq/ZMQ.java
Original file line number Diff line number Diff line change
Expand Up @@ -2416,11 +2416,16 @@ public boolean setIPv4Only(boolean v4only)
}

/**
* Set the IPv6 option for the socket.
* A value of true means IPv6 is enabled on the socket, while false means the socket will use only IPv4.
* When IPv6 is enabled the socket will connect to, or accept connections from, both IPv4 and IPv6 hosts.
* <p>Set the IPv6 option for the socket.</p>
* <p>A value of true means IPv6 is enabled on the socket, while false means the socket will use only IPv4.
* When IPv6 is enabled the socket will connect to, or accept connections from, both IPv4 and IPv6 hosts.</p>
* <p>The default value is false, unless the following system properties are set:</p>
* <ul>
* <li>java.net.preferIPv4Stack=false</li>
* <li>java.net.preferIPv6Addresses=true</li>
* </ul>
*
* @param v6 A value of true will use IPv6 sockets, while the value of false will use IPv4 sockets
* @param v6 A value of true will use IPv6 sockets, while the value of false will use IPv4 sockets only
* @return true if the option was set, otherwise false
* @see #isIPv6()
*/
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/zeromq/ZMQException.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public ZMQException(String message, int errno)
code = errno;
}

public ZMQException(String message, int errno, Throwable cause)
{
super(message, cause);
code = errno;
}

public int getErrorCode()
{
return code;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/zmq/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ public Options()
maxMsgSize = -1;
recvTimeout = -1;
sendTimeout = -1;
ipv6 = false;
ipv6 = "false".equals(System.getProperty("java.net.preferIPv4Stack", null)) ||
"true".equals(System.getProperty("java.net.preferIPv6Addresses", null));
immediate = true;
filter = false;
recvIdentity = false;
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/zmq/io/net/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public interface IZAddress

private final NetProtocol protocol;
private final String address;
// private final boolean ipv4only;

private IZAddress resolved;

Expand All @@ -40,7 +39,6 @@ public Address(SocketAddress socketAddress)
this.address = sockAddr.getAddress().getHostAddress() + ":" + sockAddr.getPort();
protocol = NetProtocol.tcp;
resolved = null;
// ipv4only = !(sockAddr.getAddress() instanceof Inet6Address);
}

@Override
Expand Down
37 changes: 25 additions & 12 deletions src/main/java/zmq/io/net/tcp/TcpAddress.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package zmq.io.net.tcp;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

import org.zeromq.ZMQException;

import zmq.ZError;
import zmq.io.net.Address;
import zmq.io.net.ProtocolFamily;
import zmq.io.net.StandardProtocolFamily;
Expand Down Expand Up @@ -77,9 +82,13 @@ public String toString(int port)
}
}

// This function enhances tcp_address_t::resolve() with ability to parse
// additional cidr-like(/xx) mask value at the end of the name string.
// Works only with remote hostnames.
/**
* @param name
* @param ipv6
* @param local ignored
* @return
* @see zmq.io.net.Address.IZAddress#resolve(java.lang.String, boolean, boolean)
*/
@Override
public InetSocketAddress resolve(String name, boolean ipv6, boolean local)
{
Expand Down Expand Up @@ -114,24 +123,28 @@ public InetSocketAddress resolve(String name, boolean ipv6, boolean local)

InetAddress addrNet = null;

// '*' as unspecified address is not accepted in Java
// '::' for IPv6 is accepted
if (addrStr.equals("*")) {
addrStr = "0.0.0.0";
addrStr = ipv6 ? "::" : "0.0.0.0";
}

try {
for (InetAddress ia : InetAddress.getAllByName(addrStr)) {
if (ipv6 && !(ia instanceof Inet6Address)) {
continue;
}
addrNet = ia;
break;
InetAddress[] addresses = InetAddress.getAllByName(addrStr);
if (ipv6) {
// prefer IPv6: return the first ipv6 or the first value if not found
addrNet = Arrays.stream(addresses).filter(i -> i instanceof Inet6Address).findFirst().orElseGet(() -> addresses[0]);
}
else {
addrNet = Arrays.stream(addresses).filter(i -> i instanceof Inet4Address).findFirst().orElseGet(() -> null);
}
}
catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
throw new ZMQException(e.getMessage(), ZError.EADDRNOTAVAIL, e);
}

if (addrNet == null) {
throw new IllegalArgumentException(name);
throw new ZMQException(addrStr + " not found matching IPv4/IPv6 settings", ZError.EADDRNOTAVAIL);
}

return new InetSocketAddress(addrNet, port);
Expand Down
17 changes: 3 additions & 14 deletions src/main/java/zmq/io/net/tcp/TcpConnecter.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,20 +267,9 @@ private boolean open() throws IOException
fd = options.selectorChooser.choose(resolved, options).openSocketChannel();
}

// IPv6 address family not supported, try automatic downgrade to IPv4.
if (fd == null && resolved.family() == StandardProtocolFamily.INET6 && options.ipv6) {
resolved = addr.resolve(false);
if (resolved == null) {
return false;
}
// TODO V4 automatic downgrade to IPV4
sa = resolved.address();
fd = SocketChannel.open();
}
assert (fd != null);

// On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
// Switch it on in such cases.
// On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
// Switch it on in such cases.
// The method enableIpv4Mapping is empty. Still to be written
if (resolved.family() == StandardProtocolFamily.INET6) {
TcpUtils.enableIpv4Mapping(fd);
}
Expand Down
11 changes: 3 additions & 8 deletions src/main/java/zmq/io/net/tcp/TcpListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,9 @@ public boolean setAddress(final String addr)
fd = options.selectorChooser.choose(address, options).openServerSocketChannel();
}

// IPv6 address family not supported, try automatic downgrade to IPv4.
if (fd == null && address.family() == StandardProtocolFamily.INET6 && options.ipv6) {
// TODO V4 automatic downgrade to IPV4
}
assert (fd != null);

// On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
// Switch it on in such cases.
// On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
// Switch it on in such cases.
// The method enableIpv4Mapping is empty. Still to be written
if (address.family() == StandardProtocolFamily.INET6) {
TcpUtils.enableIpv4Mapping(fd);
}
Expand Down
25 changes: 0 additions & 25 deletions src/test/java/zmq/io/net/TcpAddressTest.java

This file was deleted.

5 changes: 3 additions & 2 deletions src/test/java/zmq/io/net/TestAddress.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.zeromq.ZMQException;

public class TestAddress
{
Expand All @@ -25,8 +26,8 @@ public void testResolvedToString()
assertTrue(resolved.matches("tcp://\\d+\\.\\d+\\.\\d+\\.\\d+:90"));
}

@Test(expected = IllegalArgumentException.class)
public void testInvaid()
@Test(expected = ZMQException.class)
public void testInvalid()
{
new Address("tcp", "ggglocalhostxxx:90").resolve(false);
}
Expand Down
152 changes: 152 additions & 0 deletions src/test/java/zmq/io/net/tcp/TcpAddressTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package zmq.io.net.tcp;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.zeromq.ZMQException;

import zmq.ZError;
import zmq.io.net.Address;
import zmq.io.net.NetProtocol;
import zmq.util.Utils;

public class TcpAddressTest
{
@Test
public void parsesIpv6AddressSimple() throws IOException
{
String addressString = "2000::a1";
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(), addressString + ":" + port);
addr.resolve(true);
InetSocketAddress expected = new InetSocketAddress(addressString, port);
Address.IZAddress resolved = addr.resolved();
assertEquals(expected, resolved.address());
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals(port, sa.getPort());
}

@Test
public void parsesIpv6AddressBracket() throws IOException
{
String addressString = "2000::a1";
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(), "[" + addressString + "]:" + port);
addr.resolve(true);
InetSocketAddress expected = new InetSocketAddress(addressString, port);
Address.IZAddress resolved = addr.resolved();
assertEquals(expected, resolved.address());
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals(port, sa.getPort());
}

@Test
public void parsesIpv6AddressNotWanted() throws IOException
{
try {
String addressString = "2000::a1";
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(),
addressString + ":" + port);
addr.resolve(false);
InetSocketAddress expected = new InetSocketAddress(addressString,
port);
Address.IZAddress resolved = addr.resolved();
assertEquals(expected, resolved.address());
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals(port, sa.getPort());
Assert.fail();
}
catch (ZMQException e) {
Assert.assertEquals(ZError.EADDRNOTAVAIL, e.getErrorCode());
Assert.assertEquals("2000::a1 not found matching IPv4/IPv6 settings", e.getMessage());
}
}

@Ignore // Fails on both Circleci and Travis
@Test
public void testGoodIPv6Google()
{
Address addr = new Address(NetProtocol.tcp.name(), "www.google.com:80");
addr.resolve(true);
Address.IZAddress resolved = addr.resolved();
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals(80, sa.getPort());
}

@Test
public void testGoodIP46Google()
{
Address addr = new Address(NetProtocol.tcp.name(), "www.google.com:80");
addr.resolve(false);
Address.IZAddress resolved = addr.resolved();
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet4Address);
Assert.assertEquals(80, sa.getPort());
}

@Test
public void testBad()
{
try {
Address addr = new Address(NetProtocol.tcp.name(), "lclhost.:80");
addr.resolve(true);
addr.resolved();
Assert.fail();
}
catch (ZMQException e) {
Assert.assertEquals(ZError.EADDRNOTAVAIL, e.getErrorCode());
Assert.assertEquals(e.getCause().getMessage(), e.getMessage());
}
}

@Test
public void testUnspecifiedIPv6DoubleColon() throws IOException
{
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(), ":::" + port);
addr.resolve(true);
Address.IZAddress resolved = addr.resolved();
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals("0:0:0:0:0:0:0:0", sa.getHostString());
Assert.assertEquals(port, sa.getPort());
}

@Test
public void testUnspecifiedIPv6Star() throws IOException
{
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(), "*:" + port);
addr.resolve(true);
Address.IZAddress resolved = addr.resolved();
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet6Address);
Assert.assertEquals("0:0:0:0:0:0:0:0", sa.getHostString());
Assert.assertEquals(port, sa.getPort());
}

@Test
public void testUnspecifiedIPv4() throws IOException
{
int port = Utils.findOpenPort();
Address addr = new Address(NetProtocol.tcp.name(), "*:" + port);
addr.resolve(false);
Address.IZAddress resolved = addr.resolved();
InetSocketAddress sa = (InetSocketAddress) resolved.address();
Assert.assertTrue(sa.getAddress() instanceof Inet4Address);
Assert.assertEquals("0.0.0.0", sa.getHostString());
Assert.assertEquals(port, sa.getPort());
}
}

0 comments on commit 0c987cc

Please sign in to comment.