--- old/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaServerSocketChannelImpl.java 2018-12-04 19:57:49.542205394 +0000 +++ new/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaServerSocketChannelImpl.java 2018-12-04 19:57:49.085977395 +0000 @@ -27,6 +27,7 @@ import java.io.FileDescriptor; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ProtocolFamily; import java.net.ServerSocket; @@ -41,6 +42,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.channels.UnsupportedAddressTypeException; import java.nio.channels.spi.SelectorProvider; import java.util.Collections; import java.util.HashSet; @@ -54,6 +56,8 @@ import sun.nio.ch.SelChImpl; import sun.nio.ch.SelectionKeyImpl; import sun.net.ext.RdmaSocketOptions; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; public class RdmaServerSocketChannelImpl extends ServerSocketChannel @@ -98,12 +102,11 @@ throws IOException { super(checkSupported(sp)); Objects.requireNonNull(family, "'family' is null"); - if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { + if (!(family == INET || family == INET6)) { throw new UnsupportedOperationException( "Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6) { + if (family == INET6) { if (!Net.isIPv6Available()) { throw new UnsupportedOperationException( "IPv6 not available"); @@ -194,6 +197,15 @@ return DefaultOptionsHolder.defaultOptions; } + private final InetSocketAddress anyLocalAddress() throws IOException { + if (family == INET) + return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0); + else if (family == INET6) + return new InetSocketAddress(InetAddress.getByName("::"), 0); + else + throw new UnsupportedAddressTypeException(); + } + @Override public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { @@ -202,7 +214,7 @@ if (localAddress != null) throw new AlreadyBoundException(); InetSocketAddress isa = (local == null) - ? new InetSocketAddress(0) + ? anyLocalAddress() : RdmaNet.checkAddress(local, family); SecurityManager sm = System.getSecurityManager(); if (sm != null) --- old/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketChannelImpl.java 2018-12-04 19:57:59.191027398 +0000 +++ new/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketChannelImpl.java 2018-12-04 19:57:58.718791398 +0000 @@ -35,7 +35,6 @@ import java.net.Socket; import java.net.SocketAddress; import java.net.SocketOption; -import java.net.StandardProtocolFamily; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.AlreadyBoundException; @@ -47,6 +46,7 @@ import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; +import java.nio.channels.UnsupportedAddressTypeException; import java.nio.channels.spi.SelectorProvider; import java.util.Collections; import java.util.HashSet; @@ -56,10 +56,12 @@ import sun.net.ext.RdmaSocketOptions; import sun.nio.ch.IOStatus; import sun.nio.ch.IOUtil; -import sun.nio.ch.Net; import sun.nio.ch.NativeThread; +import sun.nio.ch.Net; import sun.nio.ch.SelChImpl; import sun.nio.ch.SelectionKeyImpl; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; public class RdmaSocketChannelImpl extends SocketChannel @@ -67,7 +69,7 @@ { // The protocol family of the socket private final ProtocolFamily family; - + private static RdmaSocketDispatcher nd; private final FileDescriptor fd; private final int fdVal; @@ -103,7 +105,7 @@ private static final SelectorProvider checkSupported(SelectorProvider sp) { if (unsupported != null) throw new UnsupportedOperationException(unsupported.getMessage(), - unsupported); + unsupported); else return sp; } @@ -112,13 +114,11 @@ throws IOException { super(checkSupported(sp)); - Objects.requireNonNull(family, "'family' is null"); - if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { - throw new UnsupportedOperationException( - "Protocol family not supported"); + Objects.requireNonNull(family, "null family"); + if (!(family == INET || family == INET6)) { + throw new UnsupportedOperationException("Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6) { + if (family == INET6) { if (!Net.isIPv6Available()) { throw new UnsupportedOperationException("IPv6 not available"); } @@ -129,12 +129,11 @@ this.fdVal = IOUtil.fdVal(fd); } - RdmaSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, - InetSocketAddress isa) throws IOException { + RdmaSocketChannelImpl(SelectorProvider sp, + FileDescriptor fd, + InetSocketAddress isa) throws IOException { super(checkSupported(sp)); - this.family = Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET; + this.family = Net.isIPv6Available() ? INET6 : INET; this.fd = fd; this.fdVal = IOUtil.fdVal(fd); synchronized (stateLock) { @@ -475,6 +474,15 @@ } } + private final InetSocketAddress anyLocalAddress() throws IOException { + if (family == INET) + return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0); + else if (family == INET6) + return new InetSocketAddress(InetAddress.getByName("::"), 0); + else + throw new UnsupportedAddressTypeException(); + } + @Override public SocketChannel bind(SocketAddress local) throws IOException { readLock.lock(); @@ -487,9 +495,9 @@ throw new ConnectionPendingException(); if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa = (local == null) ? - new InetSocketAddress(0) - : RdmaNet.checkAddress(local, family); + InetSocketAddress isa = (local == null) + ? anyLocalAddress() + : RdmaNet.checkAddress(local, family); SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkListen(isa.getPort()); --- old/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketImpl.java 2018-12-04 19:58:10.272565397 +0000 +++ new/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketImpl.java 2018-12-04 19:58:09.692275396 +0000 @@ -25,34 +25,29 @@ package jdk.internal.net.rdma; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.FileDescriptor; -import java.lang.reflect.Field; -import java.net.InetAddress; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.ProtocolFamily; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; import java.net.SocketImpl; import java.net.SocketOption; -import java.net.SocketException; -import java.net.StandardProtocolFamily; -import java.net.UnknownHostException; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.InetSocketAddress; -import java.net.StandardSocketOptions; import java.net.SocketOptions; -import java.security.AccessController; -import java.security.PrivilegedAction; +import java.net.StandardSocketOptions; +import java.net.UnknownHostException; import java.util.Objects; import java.util.Set; import sun.nio.ch.Net; -import sun.net.ConnectionResetException; -import sun.net.ext.RdmaSocketOptions; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; public abstract class RdmaSocketImpl extends SocketImpl { @@ -122,14 +117,15 @@ } public RdmaSocketImpl(ProtocolFamily family) { - this(checkSupported()); - Objects.requireNonNull(family, "'family' is null"); - if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { - throw new UnsupportedOperationException( - "Protocol family not supported"); + this(checkSupported(), family); + } + + private RdmaSocketImpl(Void unused, ProtocolFamily family) { + Objects.requireNonNull(family, "null family"); + if (!(family == INET || family == INET6)) { + throw new UnsupportedOperationException("Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6) { + if (family == INET6) { if (!Net.isIPv6Available()) { throw new UnsupportedOperationException( "IPv6 not available"); @@ -138,8 +134,6 @@ this.family = family; } - private RdmaSocketImpl(Void unused) { } - private static volatile boolean checkedRdma; private static volatile boolean isRdmaAvailable; @@ -175,8 +169,7 @@ if (stream) { fd = new FileDescriptor(); - boolean preferIPv6 = Net.isIPv6Available() && - (family != StandardProtocolFamily.INET); + boolean preferIPv6 = Net.isIPv6Available() && (family != INET); rdmaSocketCreate(preferIPv6, true); } } @@ -202,14 +195,10 @@ } protected void connect(InetAddress address, int port) throws IOException { - if (family == StandardProtocolFamily.INET - && !(address instanceof Inet4Address)) - throw new IllegalArgumentException( - "address type not match"); - if (family == StandardProtocolFamily.INET6 - && !(address instanceof Inet6Address)) - throw new IllegalArgumentException( - "address type not match"); + if (family == INET && !(address instanceof Inet4Address)) + throw new IllegalArgumentException("address type mismatch"); + if (family == INET6 && !(address instanceof Inet6Address)) + throw new IllegalArgumentException("address type mismatch"); this.port = port; this.address = address; @@ -230,14 +219,10 @@ throw new IllegalArgumentException("unsupported address type"); InetSocketAddress addr = (InetSocketAddress) address; InetAddress ia = addr.getAddress(); - if (family == StandardProtocolFamily.INET - && !(ia instanceof Inet4Address)) - throw new IllegalArgumentException( - "address type not match"); - if (family == StandardProtocolFamily.INET6 - && !(ia instanceof Inet6Address)) - throw new IllegalArgumentException( - "address type not match"); + if (family == INET && !(ia instanceof Inet4Address)) + throw new IllegalArgumentException("address type mismatch"); + if (family == INET6 && !(ia instanceof Inet6Address)) + throw new IllegalArgumentException("address type mismatch"); if (addr.isUnresolved()) throw new UnknownHostException(addr.getHostName()); this.port = addr.getPort(); @@ -372,8 +357,7 @@ throws IOException { try { acquireFD(); - boolean preferIPv6 = Net.isIPv6Available() && - (family != StandardProtocolFamily.INET); + boolean preferIPv6 = Net.isIPv6Available() && (family != INET); try { rdmaSocketConnect(preferIPv6, address, port, timeout); synchronized (fdLock) { @@ -390,20 +374,28 @@ } } + private final InetAddress anyLocalAddress() throws IOException { + if (family == INET) + return InetAddress.getByName("0.0.0.0"); + else if (family == INET6) + return InetAddress.getByName("::"); + else + throw new IllegalArgumentException("Unsupported address type " + family); + } + protected synchronized void bind(InetAddress address, int lport) throws IOException { if (address == null) throw new IllegalArgumentException("address is null"); - if (family == StandardProtocolFamily.INET - && !(address instanceof Inet4Address)) - throw new IllegalArgumentException( - "address type not match"); - if (family == StandardProtocolFamily.INET6 - && !(address instanceof Inet6Address)) - throw new IllegalArgumentException( - "address type not match"); - boolean preferIPv6 = Net.isIPv6Available() && - (family != StandardProtocolFamily.INET); + + if (address.isAnyLocalAddress()) + address = anyLocalAddress(); + + if (family == INET && !(address instanceof Inet4Address)) + throw new IllegalArgumentException("address type mismatch"); + if (family == INET6 && !(address instanceof Inet6Address)) + throw new IllegalArgumentException("address type mismatch"); + boolean preferIPv6 = Net.isIPv6Available() && (family != INET); rdmaSocketBind(preferIPv6, address, lport); } --- /dev/null 2018-11-30 19:45:42.612000000 +0000 +++ new/test/jdk/jdk/net/RdmaSockets/rsocket/NullBind.java 2018-12-04 19:58:26.765045791 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8195160 + * @summary Tests binding with null ( automatically assigned address ) + * @requires (os.family == "linux") + * @library /test/lib + * @build RsocketTest + * @run testng/othervm NullBind + * @run testng/othervm -Djava.net.preferIPv6Addresses=true NullBind + */ + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import org.testng.SkipException; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.String.format; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; +import static jdk.net.RdmaSockets.*; +import static org.testng.Assert.assertTrue; + +public class NullBind { + + @BeforeTest + public void setup() throws Exception { + if (!RsocketTest.isRsocketAvailable()) + throw new SkipException("rsocket is not available"); + } + + @DataProvider(name = "families") + public Object[][] families() { + return new Object[][] { + { INET, Inet4Address.class }, + { INET6, Inet6Address.class } + }; + } + + @Test(dataProvider = "families") + public void testSocket(ProtocolFamily family, + Class expectedClass) + throws IOException + { + try (Socket s = openSocket(family)) { + s.bind(null); + InetAddress addr = s.getLocalAddress(); + //TODO: Argh! still a family issue in Socket.getLocalAddress + //assertTrue(expectedClass.isAssignableFrom(addr.getClass()), + // format("Excepted %s got: %s", expectedClass, addr)); + assertTrue(addr.isAnyLocalAddress(), + format("Expected any local address, got: %s", addr)); + } + } + + @Test(dataProvider = "families") + public void testServerSocket(ProtocolFamily family, + Class expectedClass) + throws IOException + { + try (ServerSocket ss = openServerSocket(family)) { + ss.bind(null); + InetAddress addr = ss.getInetAddress(); + assertTrue(expectedClass.isAssignableFrom(addr.getClass()), + format("Excepted %s got: %s", expectedClass, addr)); + assertTrue(addr.isAnyLocalAddress(), + format("Expected any local address, got: %s", addr)); + } + } + + @Test(dataProvider = "families") + public void testSocketChannel(ProtocolFamily family, + Class expectedClass) + throws IOException + { + try (SocketChannel sc = openSocketChannel(family)) { + sc.bind(null); + InetAddress addr = ((InetSocketAddress)sc.getLocalAddress()).getAddress(); + assertTrue(expectedClass.isAssignableFrom(addr.getClass()), + format("Excepted %s got: %s", expectedClass, addr)); + assertTrue(addr.isAnyLocalAddress(), + format("Expected any local address, got: %s", addr)); + } + } + + @Test(dataProvider = "families") + public void testServerSocketChannel(ProtocolFamily family, + Class expectedClass) + throws IOException + { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + InetAddress addr = ((InetSocketAddress)ssc.getLocalAddress()).getAddress(); + assertTrue(expectedClass.isAssignableFrom(addr.getClass()), + format("Excepted %s got: %s", expectedClass, addr)); + assertTrue(addr.isAnyLocalAddress(), + format("Expected any local address, got: %s", addr)); + } + } +}