8233141: DatagramSocket.send doesn't specify exception thrown when no target address

DatagramSocket and MulticastSocket send methods are changed to throw IllegalArgumentException if no target address can be determined.

Reviewed-by: alanb
This commit is contained in:
Daniel Fuchs 2019-11-18 16:48:05 +00:00
parent 91b7fd7659
commit be18a54cb1
4 changed files with 188 additions and 18 deletions

View file

@ -646,7 +646,9 @@ class DatagramSocket implements java.io.Closeable {
* if this socket has an associated channel, * if this socket has an associated channel,
* and the channel is in non-blocking mode. * and the channel is in non-blocking mode.
* @throws IllegalArgumentException if the socket is connected, * @throws IllegalArgumentException if the socket is connected,
* and connected address and packet address differ. * and connected address and packet address differ, or
* if the socket is not connected and the packet address
* is not set.
* *
* @see java.net.DatagramPacket * @see java.net.DatagramPacket
* @see SecurityManager#checkMulticast(InetAddress) * @see SecurityManager#checkMulticast(InetAddress)
@ -655,12 +657,15 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void send(DatagramPacket p) throws IOException { public void send(DatagramPacket p) throws IOException {
InetAddress packetAddress = null;
synchronized (p) { synchronized (p) {
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
checkAddress (p.getAddress(), "send"); InetAddress packetAddress = p.getAddress();
checkAddress (packetAddress, "send");
if (connectState == ST_NOT_CONNECTED) { if (connectState == ST_NOT_CONNECTED) {
if (packetAddress == null) {
throw new IllegalArgumentException("Address not set");
}
// check the address is ok with the security manager on every send. // check the address is ok with the security manager on every send.
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
@ -669,16 +674,15 @@ class DatagramSocket implements java.io.Closeable {
// while you are trying to send the packet for example // while you are trying to send the packet for example
// after the security check but before the send. // after the security check but before the send.
if (security != null) { if (security != null) {
if (p.getAddress().isMulticastAddress()) { if (packetAddress.isMulticastAddress()) {
security.checkMulticast(p.getAddress()); security.checkMulticast(packetAddress);
} else { } else {
security.checkConnect(p.getAddress().getHostAddress(), security.checkConnect(packetAddress.getHostAddress(),
p.getPort()); p.getPort());
} }
} }
} else { } else {
// we're connected // we're connected
packetAddress = p.getAddress();
if (packetAddress == null) { if (packetAddress == null) {
p.setAddress(connectedAddress); p.setAddress(connectedAddress);
p.setPort(connectedPort); p.setPort(connectedPort);

View file

@ -29,6 +29,7 @@ import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Set; import java.util.Set;
import java.net.PortUnreachableException;
/** /**
* The multicast datagram socket class is useful for sending * The multicast datagram socket class is useful for sending
@ -643,11 +644,19 @@ class MulticastSocket extends DatagramSocket {
* @param ttl optional time to live for multicast packet. * @param ttl optional time to live for multicast packet.
* default ttl is 1. * default ttl is 1.
* *
* @throws IOException is raised if an error occurs i.e * @throws IOException is raised if an error occurs i.e
* error while setting ttl. * error while setting ttl.
* @throws SecurityException if a security manager exists and its * @throws SecurityException if a security manager exists and its
* {@code checkMulticast} or {@code checkConnect} * {@code checkMulticast} or {@code checkConnect}
* method doesn't allow the send. * method doesn't allow the send.
* @throws PortUnreachableException may be thrown if the socket is connected
* to a currently unreachable destination. Note, there is no
* guarantee that the exception will be thrown.
* @throws IllegalArgumentException if the socket is connected,
* and connected address and packet address differ, or
* if the socket is not connected and the packet address
* is not set.
*
* *
* @deprecated Use the following code or its equivalent instead: * @deprecated Use the following code or its equivalent instead:
* ...... * ......
@ -667,32 +676,34 @@ class MulticastSocket extends DatagramSocket {
throws IOException { throws IOException {
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
checkAddress(p.getAddress(), "send");
synchronized(ttlLock) { synchronized(ttlLock) {
synchronized(p) { synchronized(p) {
InetAddress packetAddress = p.getAddress();
checkAddress(packetAddress, "send");
if (connectState == ST_NOT_CONNECTED) { if (connectState == ST_NOT_CONNECTED) {
if (packetAddress == null) {
throw new IllegalArgumentException("Address not set");
}
// Security manager makes sure that the multicast address // Security manager makes sure that the multicast address
// is allowed one and that the ttl used is less // is allowed one and that the ttl used is less
// than the allowed maxttl. // than the allowed maxttl.
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
if (p.getAddress().isMulticastAddress()) { if (packetAddress.isMulticastAddress()) {
security.checkMulticast(p.getAddress(), ttl); security.checkMulticast(packetAddress, ttl);
} else { } else {
security.checkConnect(p.getAddress().getHostAddress(), security.checkConnect(packetAddress.getHostAddress(),
p.getPort()); p.getPort());
} }
} }
} else { } else {
// we're connected // we're connected
InetAddress packetAddress = null;
packetAddress = p.getAddress();
if (packetAddress == null) { if (packetAddress == null) {
p.setAddress(connectedAddress); p.setAddress(connectedAddress);
p.setPort(connectedPort); p.setPort(connectedPort);
} else if ((!packetAddress.equals(connectedAddress)) || } else if ((!packetAddress.equals(connectedAddress)) ||
p.getPort() != connectedPort) { p.getPort() != connectedPort) {
throw new SecurityException("connected address and packet address" + throw new IllegalArgumentException("connected address and packet address" +
" differ"); " differ");
} }
} }

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2019, 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 8233141
* @summary DatagramSocket.send should throw IllegalArgumentException
* when the packet address is not correctly set.
* @run main AddressNotSet
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketAddress;
import java.nio.channels.DatagramChannel;
import static java.lang.System.out;
public class AddressNotSet {
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
final DatagramSocket serversock;
int i;
AddressNotSet() throws Exception {
serversock = new DatagramSocket(0, loopbackAddress);
}
public static void main (String args[]) throws Exception {
new AddressNotSet().run();
}
public void run() throws Exception {
try (var ss = serversock) {
try (DatagramSocket sock = new DatagramSocket()) {
test(sock);
}
try (DatagramSocket sock = new MulticastSocket()) {
test(sock);
}
try (DatagramSocket sock = DatagramChannel.open().socket()) {
test(sock);
}
}
}
private void test(DatagramSocket sock) throws Exception {
out.println("Testing with " + sock.getClass());
InetAddress addr = loopbackAddress;
byte[] buf;
DatagramPacket p;
int port = serversock.getLocalPort();
SocketAddress connectedAddress = serversock.getLocalSocketAddress();
out.println("Checking send to non-connected address ...");
try {
out.println("Checking send with no packet address");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length);
sock.send(p);
throw new AssertionError("Expected IllegalArgumentException not received");
} catch (IllegalArgumentException x) {
out.println("Got expected exception: " + x);
}
out.println("Checking send to valid address");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length, addr, port);
sock.send(p);
serversock.receive(p);
out.println("Connecting to server address: " + connectedAddress);
sock.connect(connectedAddress);
try {
out.println("Checking send with different address than connected");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length, addr, port+1);
sock.send(p);
throw new AssertionError("Expected IllegalArgumentException not received");
} catch (IllegalArgumentException x) {
out.println("Got expected exception: " + x);
}
out.println("Checking send to valid address");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length, addr, port);
sock.send(p);
serversock.receive(p);
if (sock instanceof MulticastSocket) {
sock.disconnect();
testTTL((MulticastSocket)sock);
}
}
private void testTTL(MulticastSocket sock) throws Exception {
out.println("Testing deprecated send TTL with " + sock.getClass());
final byte ttl = 100;
InetAddress addr = loopbackAddress;
byte[] buf;
DatagramPacket p;
int port = serversock.getLocalPort();
out.println("Checking send to non-connected address ...");
try {
out.println("Checking send with no packet address");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length);
sock.send(p,ttl);
throw new AssertionError("Expected IllegalArgumentException not received");
} catch (IllegalArgumentException x) {
out.println("Got expected exception: " + x);
}
out.println("Connecting to connected address: " + sock);
sock.connect(addr, port);
try {
out.println("Checking send with different address than connected");
buf = ("Hello, server"+(++i)).getBytes();
p = new DatagramPacket(buf, buf.length, addr, port+1);
sock.send(p, ttl);
throw new AssertionError("Expected IllegalArgumentException not received");
} catch (IllegalArgumentException x) {
out.println("Got expected exception: " + x);
}
}
}

View file

@ -110,12 +110,17 @@ public class SendDatagramToBadAddress {
} }
public void run() throws Exception { public void run() throws Exception {
if (OSsupportsFeature()) { if (OSsupportsFeature()) {
print ("running on OS that supports ICMP port unreachable"); print ("running on OS that supports ICMP port unreachable");
} }
try (DatagramSocket sock = new DatagramSocket()) {
test(sock);
}
}
private void test(DatagramSocket sock) throws Exception {
print("Testing with " + sock.getClass());
InetAddress addr = InetAddress.getLoopbackAddress(); InetAddress addr = InetAddress.getLoopbackAddress();
DatagramSocket sock = new DatagramSocket();
DatagramSocket serversock = new DatagramSocket(0); DatagramSocket serversock = new DatagramSocket(0);
DatagramPacket p; DatagramPacket p;
byte[] buf; byte[] buf;