diff --git pom.xml pom.xml index ae9c2ee..dbd7e37 100644 --- pom.xml +++ pom.xml @@ -1465,17 +1465,34 @@ Mac_OS_X-${sun.arch.data.model} - - os.windows - - - Windows - - - - cygwin - - + + os.windows + + + Windows + + + + cygwin + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -enableassertions -Xmx1900m -Djava.security.egd=file:/dev/./urandom -Djava.net.preferIPv4Stack=true + + + java.net.preferIPv4Stack + true + + + + + + + diff --git src/test/java/org/apache/hadoop/hbase/TestIPv6NIOServerSocketChannel.java src/test/java/org/apache/hadoop/hbase/TestIPv6NIOServerSocketChannel.java new file mode 100644 index 0000000..f31e2c2 --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/TestIPv6NIOServerSocketChannel.java @@ -0,0 +1,129 @@ +package org.apache.hadoop.hbase; + +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.nio.channels.ServerSocketChannel; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * This tests whether ServerSocketChannel works over ipv6, which Zookeeper + * depends on. On Windows Oracle JDK 6, creating a ServerSocketChannel throws + * java.net.SocketException: Address family not supported by protocol family + * exception. It is a known JVM bug, seems to be only resolved for JDK7: + * http://bugs.sun.com/view_bug.do?bug_id=6230761 + * + * For this test, we check that whether we are effected by this bug, and if so + * the test ensures that we are running with java.net.preferIPv4Stack=true, so + * that ZK will not fail to bind to ipv6 address using ClientCnxnSocketNIO. + */ +@Category(SmallTests.class) +public class TestIPv6NIOServerSocketChannel { + + private static final Log LOG = LogFactory.getLog(TestIPv6NIOServerSocketChannel.class); + + /** + * Creates and binds a regular ServerSocket. + */ + private void bindServerSocket(InetAddress inetAddr) throws IOException { + InetSocketAddress addr8501 = new InetSocketAddress(inetAddr, 8501); + ServerSocket serverSocket8501 = null; + try { + serverSocket8501 = new ServerSocket(); + serverSocket8501.bind(addr8501); + } finally { + if (serverSocket8501 != null) { + serverSocket8501.close(); + } + } + } + + /** + * Creates a NIO ServerSocketChannel, and gets the ServerSocket from + * there. Then binds the obtained socket. + * This fails on Windows with Oracle JDK1.6.0u33, if the passed InetAddress is a + * IPv6 address. Works on Oracle JDK 1.7. + */ + private void bindNIOServerSocket(InetAddress inetAddr) throws IOException { + InetSocketAddress addr8502 = new InetSocketAddress(inetAddr, 8502); + ServerSocketChannel channel = null; + ServerSocket serverSocket8502 = null; + try { + channel = ServerSocketChannel.open(); + serverSocket8502 = channel.socket(); + serverSocket8502.bind(addr8502); // This does not work + } finally { + if (serverSocket8502 != null) { + serverSocket8502.close(); + } + if (channel != null) { + channel.close(); + } + } + } + + /** + * Checks whether we are effected by the JDK issue on windows, and if so + * ensures that we are running with preferIPv4Stack=true. + */ + @Test + public void testServerSocket() throws IOException { + byte[] addr = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + InetAddress inetAddr = InetAddress.getByAddress(addr); + + try { + bindServerSocket(inetAddr); + bindNIOServerSocket(inetAddr); + //if on *nix or windows JDK7, both will pass + } catch(java.net.SocketException ex) { + //On Windows JDK6, we will get expected exception: + //java.net.SocketException: Address family not supported by protocol family + //or java.net.SocketException: Protocol family not supported + Assert.assertFalse(ex.getClass().isInstance(BindException.class)); + Assert.assertTrue(ex.getMessage().toLowerCase().contains("protocol family")); + LOG.info("Received expected exception:"); + LOG.info(ex); + + //if this is the case, ensure that we are running on preferIPv4=true + ensurePreferIPv4(); + } + } + + /** + * Checks whether we are running with java.net.preferIPv4Stack=true + */ + public void ensurePreferIPv4() throws IOException { + InetAddress[] addrs = InetAddress.getAllByName("localhost"); + for (InetAddress addr : addrs) { + LOG.info("resolved localhost as:" + addr); + Assert.assertEquals(4, addr.getAddress().length); //ensure 4 byte ipv4 address + } + } + + /** + * Tests whether every InetAddress we obtain by resolving can open a + * ServerSocketChannel. + */ + @Test + public void testServerSocketFromLocalhostResolution() throws IOException { + InetAddress[] addrs = InetAddress.getAllByName("localhost"); + for (InetAddress addr : addrs) { + LOG.info("resolved localhost as:" + addr); + bindServerSocket(addr); + bindNIOServerSocket(addr); + } + } + + public static void main(String[] args) throws Exception { + TestIPv6NIOServerSocketChannel test = new TestIPv6NIOServerSocketChannel(); + test.testServerSocket(); + test.testServerSocketFromLocalhostResolution(); + } +}