changeset 58914:f41394559814

7021373: DatagramPacket exception conditions are not clear Summary: Specification is clarified by adding or clarifying @throws clauses where required Reviewed-by: alanb, chegar, darcy, dfuchs
author pconcannon
date Fri, 07 Feb 2020 11:10:41 +0000
parents 84920d352dc4
children f2cefce4859b
files src/java.base/share/classes/java/net/DatagramPacket.java test/jdk/java/net/DatagramPacket/Constructor.java test/jdk/java/net/DatagramPacket/Setters.java
diffstat 3 files changed, 325 insertions(+), 172 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/DatagramPacket.java	Fri Feb 07 10:23:35 2020 +0100
+++ b/src/java.base/share/classes/java/net/DatagramPacket.java	Fri Feb 07 11:10:41 2020 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2020, 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
@@ -35,6 +35,16 @@
  * differently, and might arrive in any order. Packet delivery is
  * not guaranteed.
  *
+ * <p>
+ * Unless otherwise specified, passing a {@code null} argument causes
+ * a {@link NullPointerException NullPointerException} to be thrown.
+ *
+ * <p>
+ * Methods and constructors of {@code DatagramPacket} accept parameters
+ * of type {@link SocketAddress}. {@code DatagramPacket} supports
+ * {@link InetSocketAddress}, and may support additional {@code SocketAddress}
+ * sub-types.
+ *
  * @author  Pavani Diwanji
  * @author  Benjamin Renaud
  * @since   1.0
@@ -68,11 +78,15 @@
      * The {@code length} argument must be less than or equal to
      * {@code buf.length}.
      *
-     * @param   buf      buffer for holding the incoming datagram.
-     * @param   offset   the offset for the buffer
-     * @param   length   the number of bytes to read.
+     * @param   buf     buffer for holding the incoming datagram.
+     * @param   offset  the offset for the buffer
+     * @param   length  the number of bytes to read.
      *
-     * @since 1.2
+     * @throws  IllegalArgumentException    if the length or offset
+     *          is negative, or if the length plus the offset is
+     *          greater than the length of the packet's given buffer.
+     *
+     * @since   1.2
      */
     public DatagramPacket(byte buf[], int offset, int length) {
         setData(buf, offset, length);
@@ -87,8 +101,12 @@
      * The {@code length} argument must be less than or equal to
      * {@code buf.length}.
      *
-     * @param   buf      buffer for holding the incoming datagram.
-     * @param   length   the number of bytes to read.
+     * @param   buf     buffer for holding the incoming datagram.
+     * @param   length  the number of bytes to read.
+     *
+     * @throws  IllegalArgumentException    if the length is negative
+     *          or if the length is greater than the length of the
+     *          packet's given buffer.
      */
     public DatagramPacket(byte buf[], int length) {
         this (buf, 0, length);
@@ -101,14 +119,20 @@
      * {@code length} argument must be less than or equal to
      * {@code buf.length}.
      *
-     * @param   buf      the packet data.
-     * @param   offset   the packet data offset.
-     * @param   length   the packet data length.
-     * @param   address  the destination address.
-     * @param   port     the destination port number.
-     * @see java.net.InetAddress
+     * @param   buf     the packet data.
+     * @param   offset  the packet data offset.
+     * @param   length  the packet data length.
+     * @param   address the destination address, or {@code null}.
+     * @param   port    the destination port number.
      *
-     * @since 1.2
+     * @throws  IllegalArgumentException    if the length or offset
+     *          is negative, or if the length plus the offset is
+     *          greater than the length of the packet's given buffer,
+     *          or if the port is out of range.
+     *
+     * @see     java.net.InetAddress
+     *
+     * @since   1.2
      */
     public DatagramPacket(byte buf[], int offset, int length,
                           InetAddress address, int port) {
@@ -124,14 +148,19 @@
      * {@code length} argument must be less than or equal to
      * {@code buf.length}.
      *
-     * @param   buf      the packet data.
-     * @param   offset   the packet data offset.
-     * @param   length   the packet data length.
-     * @param   address  the destination socket address.
-     * @throws  IllegalArgumentException if address type is not supported
-     * @see java.net.InetAddress
+     * @param   buf     the packet data.
+     * @param   offset  the packet data offset.
+     * @param   length  the packet data length.
+     * @param   address the destination socket address.
      *
-     * @since 1.4
+     * @throws  IllegalArgumentException    if address is null or its
+     *          type is not supported, or if the length or offset is
+     *          negative, or if the length plus the offset is greater
+     *          than the length of the packet's given buffer.
+     *
+     * @see     java.net.InetAddress
+     *
+     * @since   1.4
      */
     public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) {
         setData(buf, offset, length);
@@ -144,10 +173,15 @@
      * host. The {@code length} argument must be less than or equal
      * to {@code buf.length}.
      *
-     * @param   buf      the packet data.
-     * @param   length   the packet length.
-     * @param   address  the destination address.
-     * @param   port     the destination port number.
+     * @param   buf     the packet data.
+     * @param   length  the packet length.
+     * @param   address the destination address, or {@code null}.
+     * @param   port    the destination port number.
+     *
+     * @throws  IllegalArgumentException    if the length is negative,
+     *          or if the length is greater than the length of the
+     *          packet's given buffer, or if the port is out of range.
+     *
      * @see     java.net.InetAddress
      */
     public DatagramPacket(byte buf[], int length,
@@ -161,12 +195,18 @@
      * host. The {@code length} argument must be less than or equal
      * to {@code buf.length}.
      *
-     * @param   buf      the packet data.
-     * @param   length   the packet length.
-     * @param   address  the destination address.
-     * @throws  IllegalArgumentException if address type is not supported
-     * @since 1.4
+     * @param   buf     the packet data.
+     * @param   length  the packet length.
+     * @param   address the destination address.
+     *
+     * @throws  IllegalArgumentException    if address is null or its type is
+     *          not supported, or if the length is negative, or if the length
+     *          is greater than the length of the packet's given buffer, or
+     *          if the port is out of range.
+     *
      * @see     java.net.InetAddress
+     *
+     * @since   1.4
      */
     public DatagramPacket(byte buf[], int length, SocketAddress address) {
         this(buf, 0, length, address);
@@ -238,20 +278,20 @@
      * Set the data buffer for this packet. This sets the
      * data, length and offset of the packet.
      *
-     * @param buf the buffer to set for this packet
+     * @param   buf     the buffer to set for this packet
+     * @param   offset  the offset into the data
+     * @param   length  the length of the data
+     *          and/or the length of the buffer used to receive data
      *
-     * @param offset the offset into the data
+     * @throws  IllegalArgumentException    if the length or offset
+     *          is negative, or if the length plus the offset is
+     *          greater than the length of the packet's given buffer.
      *
-     * @param length the length of the data
-     *       and/or the length of the buffer used to receive data
+     * @see     #getData
+     * @see     #getOffset
+     * @see     #getLength
      *
-     * @throws    NullPointerException if the argument is null
-     *
-     * @see #getData
-     * @see #getOffset
-     * @see #getLength
-     *
-     * @since 1.2
+     * @since   1.2
      */
     public synchronized void setData(byte[] buf, int offset, int length) {
         /* this will check to see if buf is null */
@@ -269,9 +309,12 @@
     /**
      * Sets the IP address of the machine to which this datagram
      * is being sent.
-     * @param iaddr the {@code InetAddress}
+     *
+     * @param   iaddr   the {@code InetAddress}, or {@code null}.
+     *
+     * @see     #getAddress()
+     *
      * @since   1.1
-     * @see #getAddress()
      */
     public synchronized void setAddress(InetAddress iaddr) {
         address = iaddr;
@@ -280,9 +323,14 @@
     /**
      * Sets the port number on the remote host to which this datagram
      * is being sent.
-     * @param iport the port number
+     *
+     * @param   iport   the port number
+     *
+     * @throws  IllegalArgumentException    if the port is out of range
+     *
+     * @see     #getPort()
+     *
      * @since   1.1
-     * @see #getPort()
      */
     public synchronized void setPort(int iport) {
         if (iport < 0 || iport > 0xFFFF) {
@@ -295,12 +343,14 @@
      * Sets the SocketAddress (usually IP address + port number) of the remote
      * host to which this datagram is being sent.
      *
-     * @param address the {@code SocketAddress}
-     * @throws  IllegalArgumentException if address is null or is a
-     *          SocketAddress subclass not supported by this socket
+     * @param   address the {@code SocketAddress}
      *
-     * @since 1.4
-     * @see #getSocketAddress
+     * @throws  IllegalArgumentException    if address is null or is a
+     *          SocketAddress subclass not supported.
+     *
+     * @see     #getSocketAddress
+     *
+     * @since   1.4
      */
     public synchronized void setSocketAddress(SocketAddress address) {
         if (address == null || !(address instanceof InetSocketAddress))
@@ -316,9 +366,11 @@
      * Gets the SocketAddress (usually IP address + port number) of the remote
      * host that this packet is being sent to or is coming from.
      *
-     * @return the {@code SocketAddress}
-     * @since 1.4
-     * @see #setSocketAddress
+     * @return  the {@code SocketAddress}
+     *
+     * @see     #setSocketAddress
+     *
+     * @since   1.4
      */
     public synchronized SocketAddress getSocketAddress() {
         return new InetSocketAddress(getAddress(), getPort());
@@ -329,14 +381,12 @@
      * this DatagramPacket set to 0, and the length set to
      * the length of {@code buf}.
      *
-     * @param buf the buffer to set for this packet.
+     * @param   buf     the buffer to set for this packet.
      *
-     * @throws    NullPointerException if the argument is null.
+     * @see     #getLength
+     * @see     #getData
      *
-     * @see #getLength
-     * @see #getData
-     *
-     * @since 1.1
+     * @since   1.1
      */
     public synchronized void setData(byte[] buf) {
         if (buf == null) {
@@ -355,16 +405,16 @@
      * will be used for receiving data. The length must be lesser or
      * equal to the offset plus the length of the packet's buffer.
      *
-     * @param length the length to set for this packet.
+     * @param   length      the length to set for this packet.
      *
-     * @throws    IllegalArgumentException if the length is negative
-     * of if the length is greater than the packet's data buffer
-     * length.
+     * @throws  IllegalArgumentException    if the length is negative,
+     *          or if the length plus the offset is greater than the
+     *          length of the packet's data buffer.
      *
-     * @see #getLength
-     * @see #setData
+     * @see     #getLength
+     * @see     #setData
      *
-     * @since 1.1
+     * @since   1.1
      */
     public synchronized void setLength(int length) {
         if ((length + offset) > buf.length || length < 0 ||
--- a/test/jdk/java/net/DatagramPacket/Constructor.java	Fri Feb 07 10:23:35 2020 +0100
+++ b/test/jdk/java/net/DatagramPacket/Constructor.java	Fri Feb 07 11:10:41 2020 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, 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
@@ -22,130 +22,98 @@
  */
 
 /* @test
- *
- * @bug 4091803
- *
+ * @bug 4091803 7021373
  * @summary this tests that the constructor of DatagramPacket rejects
- * bogus arguments properly.
- *
- * @author Benjamin Renaud
+ *          bogus arguments properly.
+ * @run testng Constructor
  */
-import java.io.*;
-import java.net.*;
-import java.util.*;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.expectThrows;
 
 public class Constructor {
 
-    public static void main(String[] args) throws Exception {
-        testNullPacket();
-        testNegativeBufferLength();
-        testPacketLengthTooLarge();
-        testNegativePortValue();
-        testPortValueTooLarge();
-        testSimpleConstructor();
-        testFullConstructor();
-        System.err.println("all passed!");
+    private static final byte[] buf = new byte[128];
+
+    private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress();
+    private static final Class<NullPointerException> NPE = NullPointerException.class;
+    private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
+
+    @Test
+    public void testNullPacket() {
+        expectThrows(NPE,
+                () -> new DatagramPacket(null, 100));
+    }
+    @Test
+    public void testNull() throws Exception {
+        expectThrows(NPE, () -> new DatagramPacket(null, 100));
+        expectThrows(NPE, () -> new DatagramPacket(null, 0, 10));
+        expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, LOOPBACK, 80));
+        expectThrows(NPE, () -> new DatagramPacket(null, 10, LOOPBACK, 80));
+        expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, new InetSocketAddress(80)));
+        expectThrows(NPE, () -> new DatagramPacket(null, 10, new InetSocketAddress(80)));
+
+        // no Exception expected for null addresses
+        new DatagramPacket(buf, 10, null, 0);
+        new DatagramPacket(buf, 10, 10, null, 0);
     }
 
-    static void testNullPacket() throws Exception {
-        boolean error = true;
-        try {
-            new DatagramPacket(null, 100);
-        } catch (NullPointerException e) {
-            /* correct exception */
-            error = false;
-        }
-        if (error) {
-            throw new RuntimeException("test 1 failed.");
-        }
+    @Test
+    public void testNegativeBufferLength() {
+        /* length lesser than buffer length */
+        expectThrows(IAE,
+                () -> new DatagramPacket(buf, -128));
     }
 
-    static void testNegativeBufferLength() throws Exception {
-        boolean error = true;
-        byte[] buf = new byte[128];
-        try {
-            /* length lesser than buffer length */
-            new DatagramPacket(buf, -128);
-        } catch (IllegalArgumentException e) {
-            /* correct exception */
-            error = false;
-        }
-        if (error) {
-            throw new RuntimeException("test 2 failed.");
-        }
+    @Test
+    public void testPacketLengthTooLarge() {
+        /* length greater than buffer length */
+        expectThrows(IAE,
+                () -> new DatagramPacket(buf, 256));
     }
 
-    static void testPacketLengthTooLarge() throws Exception {
-        boolean error = true;
-        byte[] buf = new byte[128];
-        try {
-            /* length greater than buffer length */
-            new DatagramPacket(buf, 256);
-        } catch (IllegalArgumentException e) {
-            /* correct exception */
-            error = false;
-        }
-        if (error) {
-            throw new RuntimeException("test 3 failed.");
-        }
+    @Test
+    public void testNegativePortValue() throws Exception {
+        /* negative port */
+        InetAddress addr = InetAddress.getLocalHost();
+
+        expectThrows(IAE,
+                () -> new DatagramPacket(buf, 100, addr, -1));
     }
 
-    static void testNegativePortValue() throws Exception {
-        boolean error = true;
-        byte[] buf = new byte[128];
-        InetAddress host = InetAddress.getLocalHost();
-        try {
-            /* negative port */
-            new DatagramPacket(buf, 100, host, -1);
-        } catch (IllegalArgumentException e) {
-            /* correct exception */
-            error = false;
-        }
-        if (error) {
-            throw new RuntimeException("test 5 failed.");
-        }
+    @Test
+    public void testPortValueTooLarge() {
+        /* invalid port value */
+        expectThrows(IAE,
+                () -> new DatagramPacket(buf, 128, LOOPBACK, Integer.MAX_VALUE));
     }
 
-    static void testPortValueTooLarge() throws Exception {
-        boolean error = true;
-        byte[] buf = new byte[256];
-        InetAddress address = InetAddress.getLocalHost();
-        try {
-            /* invalid port value */
-            new DatagramPacket(buf, 256, address, Integer.MAX_VALUE);
-        } catch (IllegalArgumentException e) {
-            /* correct exception */
-            error = false;
-        }
-        if (error) {
-            throw new RuntimeException("test 6 failed.");
-        }
+    @Test
+    public void testSimpleConstructor() {
+        int offset = 10;
+        int length = 50;
+        DatagramPacket pkt = new DatagramPacket(buf, offset, length);
+
+        assertFalse((pkt.getData() != buf || pkt.getOffset() != offset ||
+                pkt.getLength() != length), "simple constructor failed");
     }
 
-    static void testSimpleConstructor() {
-        byte[] buf = new byte[128];
+    @Test
+    public void testFullConstructor() {
         int offset = 10;
         int length = 50;
-        DatagramPacket packet = new DatagramPacket(buf, offset, length);
-        if (packet.getData() != buf || packet.getOffset() != offset ||
-               packet.getLength() != length) {
-            throw new RuntimeException("simple constructor failed");
-        }
-    }
+        int port = 8080;
+        DatagramPacket packet = new DatagramPacket(buf, offset, length, LOOPBACK, port);
 
-    static void testFullConstructor() throws Exception {
-        byte[] buf = new byte[128];
-        int offset = 10;
-        int length = 50;
-        InetAddress address = InetAddress.getLocalHost();
-        int port = 8080;
-        DatagramPacket packet = new DatagramPacket(buf, offset, length,
-                                                   address, port);
-        if (packet.getData() != buf || packet.getOffset() != offset ||
-            packet.getLength() != length ||
-            packet.getAddress() != address ||
-            packet.getPort() != port) {
-            throw new RuntimeException("full constructor failed");
-        }
+        assertFalse((packet.getData() != buf || packet.getOffset() != offset ||
+                packet.getLength() != length ||
+                packet.getAddress() != LOOPBACK ||
+                packet.getPort() != port), "full constructor failed");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/DatagramPacket/Setters.java	Fri Feb 07 11:10:41 2020 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2020, 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 7021373
+ * @summary check that the DatagramPacket setter methods
+ *          throw the correct exceptions
+ * @run testng Setters
+ */
+
+
+import java.net.DatagramPacket;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.expectThrows;
+
+public class Setters {
+
+    private static final byte[] buf = new byte[128];
+
+    private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
+    private static final Class<NullPointerException> NPE = NullPointerException.class;
+
+    @Test
+    public void testSetAddress() throws Exception {
+        DatagramPacket pkt = new DatagramPacket(buf, 8);
+
+        // No Exception expected for null addresses
+        pkt.setAddress(null);
+        assertTrue(pkt.getAddress() == null);
+    }
+
+    @DataProvider
+    Object[][] data() { // add checks for setAddress with null - add getAddress to verify
+        return new Object[][]{
+                { buf,          0,      -1,     IAE  },
+                { buf,          -1,     1,      IAE  },
+                { buf,          128,    128,    IAE  },
+                { null,         0,      0,      NPE  },
+                { new byte[8],  2,      2,      null },
+                { buf,          2,      2,      null },
+                { buf,          20,     20,     null },
+        };
+    }
+
+    @Test(dataProvider = "data")
+    public void testSetData(byte[] buf,
+                            int offset,
+                            int length,
+                            Class<? extends Exception> exception) {
+        DatagramPacket pkt = new DatagramPacket(new byte[8], 8);
+
+        if (exception != null) {
+            expectThrows(exception, () -> pkt.setData(buf, offset, length));
+        } else if (buf == null) {
+            expectThrows(exception, () -> pkt.setData(buf));
+        } else {
+            pkt.setData(buf, offset, length);
+        }
+    }
+
+    @DataProvider
+    Object[][] lengths() {
+        return new Object[][]{
+                { 0,     -1,     IAE  },
+                { 8,     1,      IAE  },
+                { 4,     -2,     IAE  },
+                { 0,     9,      IAE  },
+                { 2,     2,      null },
+                { 4,     4,      null }
+        };
+    }
+
+    @Test(dataProvider = "lengths")
+    public void testSetLength(int offset, int length,
+                              Class<? extends Exception> exception) {
+        DatagramPacket pkt = new DatagramPacket(new byte[8], offset, 0);
+
+        if (exception != null) {
+            expectThrows(exception, () -> pkt.setLength(length));
+        } else {
+            pkt.setLength(length);
+        }
+    }
+
+    @DataProvider
+    Object[][] ports() {
+        return new Object[][]{
+                { -1,                IAE  },
+                { -666,              IAE  },
+                { Integer.MAX_VALUE, IAE  },
+                { 0xFFFF + 1,        IAE  },
+                { 0xFFFFFF,          IAE  },
+                { 0,                 null },
+                { 1,                 null },
+                { 666,               null },
+                { 0xFFFE,            null },
+                { 0xFFFF,            null },
+        };
+    }
+
+    @Test(dataProvider = "ports")
+    public void testSetPort(int port, Class<? extends Exception> exception) {
+        DatagramPacket pkt = new DatagramPacket(new byte[8], 0);
+
+        if (exception != null) {
+            expectThrows(exception, () -> pkt.setPort(port));
+        } else {
+            pkt.setPort(port);
+        }
+    }
+}