diff --git a/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 0d03a40859c9a28d9fe040db2fb804ed9c87f27a..f1a4995582ec01cba891701bddf79a475dcfdf0e 100644 --- a/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -44,7 +44,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl int timeout = 0; boolean connected = false; private int trafficClass = 0; - private InetAddress connectedAddress = null; + protected InetAddress connectedAddress = null; private int connectedPort = -1; /* cached socket options */ diff --git a/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java b/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java index ebd5e527ca2a292210124b56b2e611e396108336..1e713d83fab9d1624bc36631085754624af7dcc6 100644 --- a/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java +++ b/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java @@ -99,10 +99,11 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl } if (optID == SO_BINDADDR) { - if (fd != null && fd1 != null) { + if ((fd != null && fd1 != null) && !connected) { return anyLocalBoundAddr; } - return socketGetOption(optID); + int family = connectedAddress == null ? -1 : connectedAddress.family; + return socketLocalAddress(family); } else return super.getOption(optID); } @@ -161,6 +162,8 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl protected native void connect0(InetAddress address, int port) throws SocketException; + protected native Object socketLocalAddress(int family) throws SocketException; + protected native void disconnect0(int family); /** diff --git a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c index 5ca6736b903b8f91d93305fe55cc777df2f47cc8..161017754cadf65181acbcebd61b26b0a754d331 100644 --- a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c +++ b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c @@ -2181,30 +2181,6 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobj return getMulticastInterface(env, this, fd, fd1, opt); } - if (opt == java_net_SocketOptions_SO_BINDADDR) { - /* find out local IP address */ - SOCKETADDRESS him; - int len = 0; - int port; - jobject iaObj; - - len = sizeof (struct sockaddr_in); - - if (fd == -1) { - fd = fd1; /* must be IPv6 only */ - len = sizeof (struct SOCKADDR_IN6); - } - - if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "Error getting socket name"); - return NULL; - } - iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); - - return iaObj; - } - /* * Map the Java level socket option to the platform specific * level and option name. @@ -2252,6 +2228,61 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobj } } +/* + * Returns local address of the socket. + * + * Class: java_net_TwoStacksPlainDatagramSocketImpl + * Method: socketLocalAddress + * Signature: (I)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL +Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress(JNIEnv *env, jobject this, + jint family) { + + int fd=-1, fd1=-1; + SOCKETADDRESS him; + int len = 0; + int port; + jobject iaObj; + int ipv6_supported = ipv6_available(); + + fd = getFD(env, this); + if (ipv6_supported) { + fd1 = getFD1(env, this); + } + + if (fd < 0 && fd1 < 0) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", + "Socket closed"); + return NULL; + } + + /* find out local IP address */ + + len = sizeof (struct sockaddr_in); + + /* family==-1 when socket is not connected */ + if ((family == IPv6) || (family == -1 && fd == -1)) { + fd = fd1; /* must be IPv6 only */ + len = sizeof (struct SOCKADDR_IN6); + } + + if (fd == -1) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", + "Socket closed"); + return NULL; + } + + if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { + NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", + "Error getting socket name"); + return NULL; + } + iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); + + return iaObj; +} + /* * Class: java_net_TwoStacksPlainDatagramSocketImpl * Method: setTimeToLive diff --git a/test/java/net/DatagramSocket/ChangingAddress.java b/test/java/net/DatagramSocket/ChangingAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..42cc78b00a93aa05a1d9a6008d13544dffceadef --- /dev/null +++ b/test/java/net/DatagramSocket/ChangingAddress.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 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 7084030 + * @summary Tests that DatagramSocket.getLocalAddress returns the right local + * address after connect/disconnect. + */ +import java.net.*; + +public class ChangingAddress { + + static void check(DatagramSocket ds, InetAddress expected) { + InetAddress actual = ds.getLocalAddress(); + if (!expected.equals(actual)) { + throw new RuntimeException("Expected:"+expected+" Actual"+ + actual); + } + } + + public static void main(String[] args) throws Exception { + InetAddress lh = InetAddress.getLocalHost(); + SocketAddress remote = new InetSocketAddress(lh, 1234); + InetAddress wildcard = InetAddress.getByAddress + ("localhost", new byte[]{0,0,0,0}); + try (DatagramSocket ds = new DatagramSocket()) { + check(ds, wildcard); + + ds.connect(remote); + check(ds, lh); + + ds.disconnect(); + check(ds, wildcard); + } + } +}