Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8338397

Several methods on DatagramSocket and MulticastSocket do not specify behaviour when already closed or connected

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 24
    • core-libs
    • None
    • behavioral
    • minimal
    • The change only updates the API documentation to clarify the current implementation. As such, no behavioural change is expected.
    • Java API
    • SE

      Summary

      The API documentation of java.net.DatagramSocket will be updated to clarify the behaviour of some of the APIs to match the current implementation.

      Problem

      DatagramSocket class provides APIs for user applications to deal with UDP communication. connect(...) is one such API which allows users to connect the underlying socket to a particular address so that the datagram sent from the socket will be delivered only to the connected address and datagrams from only that connected address will be received by this DatagramSocket instance.

      There are 2 connect(...) methods on the DatagramSocket:

      public void connect(SocketAddress addr) throws SocketException
      public void connect(InetAddress address, int port)

      In the OpenJDK default implementation of these APIs, when the socket is already connected (through a prior call to either of these methods), then a subsequent call to connect(...) will attempt to connect to the given address. This behaviour isn't currently specified.

      Solution

      The API documentation of these 2 methods will be updated to specify that the implementation will attempt to connect to the given address even when the socket is already connected. This clarification will match the current implementation in those methods.

      While at it, the API documentation of some other methods of this class as well as the java.net.MulticastSocket class have also been updated to provide clarity on what happens if those other methods are invoked when the socket is already closed. These clarifications too match the current implementation and are being done similar to what was done in https://bugs.openjdk.org/browse/JDK-8336868.

      Specification

      diff --git a/src/java.base/share/classes/java/net/DatagramSocket.java b/src/java.base/share/classes/java/net/DatagramSocket.java
      index 9e94d1d8b6209..655b00bb8b6e1 100644
      --- a/src/java.base/share/classes/java/net/DatagramSocket.java
      +++ b/src/java.base/share/classes/java/net/DatagramSocket.java
      @@ -395,7 +395,7 @@ public DatagramSocket(int port, InetAddress laddr) throws SocketException {
            *
            * @param   addr The address and port to bind to.
            * @throws  SocketException if any error happens during the bind, or if the
      -     *          socket is already bound.
      +     *          socket is already bound or is closed.
            * @throws  SecurityException  if a security manager exists and its
            *             {@code checkListen} method doesn't allow the operation.
            * @throws IllegalArgumentException if addr is a SocketAddress subclass
      @@ -422,6 +422,11 @@ public void bind(SocketAddress addr) throws SocketException {
            * call to send or receive may throw a PortUnreachableException. Note,
            * there is no guarantee that the exception will be thrown.
            *
      +     * <p> If this socket is already connected, then this method will attempt to
      +     * connect to the given address. If this connect fails then the state of
      +     * this socket is unknown - it may or may not be connected to the address
      +     * that it was previously connected to.
      +     *
            * <p> If a security manager has been installed then it is invoked to check
            * access to the remote address. Specifically, if the given {@code address}
            * is a {@link InetAddress#isMulticastAddress multicast address},
      @@ -461,7 +466,7 @@ public void bind(SocketAddress addr) throws SocketException {
            *         not permit access to the given remote address
            *
            * @throws UncheckedIOException
      -     *         may be thrown if connect fails, for example, if the
      +     *         if the port is 0 or connect fails, for example, if the
            *         destination address is non-routable
            *
            * @see #disconnect
      @@ -484,6 +489,11 @@ public void connect(InetAddress address, int port) {
            * have not been {@linkplain #receive(DatagramPacket) received} before invoking
            * this method, may be discarded.
            *
      +     * <p> If this socket is already connected, then this method will attempt to
      +     * connect to the given address. If this connect fails then the state of
      +     * this socket is unknown - it may or may not be connected to the address
      +     * that it was previously connected to.
      +     *
            * @param   addr    The remote address.
            *
            * @throws  SocketException
      @@ -643,7 +653,7 @@ public SocketAddress getLocalSocketAddress() {
            *
            * @param      p   the {@code DatagramPacket} to be sent.
            *
      -     * @throws     IOException  if an I/O error occurs.
      +     * @throws     IOException  if an I/O error occurs, or the socket is closed.
            * @throws     SecurityException  if a security manager exists and its
            *             {@code checkMulticast} or {@code checkConnect}
            *             method doesn't allow the send.
      @@ -702,7 +712,7 @@ public void send(DatagramPacket p) throws IOException  {
            *
            * @param      p   the {@code DatagramPacket} into which to place
            *                 the incoming data.
      -     * @throws     IOException  if an I/O error occurs.
      +     * @throws     IOException  if an I/O error occurs, or the socket is closed.
            * @throws     SocketTimeoutException  if setSoTimeout was previously called
            *                 and the timeout has expired.
            * @throws     PortUnreachableException may be thrown if the socket is connected
      @@ -770,7 +780,8 @@ public int getLocalPort() {
            * operation to have effect.
            *
            * @param timeout the specified timeout in milliseconds.
      -     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @throws IllegalArgumentException if {@code timeout} is negative
            * @since   1.1
            * @see #getSoTimeout()
      @@ -784,7 +795,8 @@ public void setSoTimeout(int timeout) throws SocketException {
            * option is disabled (i.e., timeout of infinity).
            *
            * @return the setting for SO_TIMEOUT
      -     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @since   1.1
            * @see #setSoTimeout(int)
            */
      @@ -820,8 +832,8 @@ public int getSoTimeout() throws SocketException {
            * @param size the size to which to set the send buffer
            * size, in bytes. This value must be greater than 0.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @throws    IllegalArgumentException if the value is 0 or is
            * negative.
            * @see #getSendBufferSize()
      @@ -841,8 +853,8 @@ public void setSendBufferSize(int size) throws SocketException {
            * getOption(StandardSocketOptions.SO_SNDBUF)}.
            *
            * @return the value of the SO_SNDBUF option for this {@code DatagramSocket}
      -     * @throws    SocketException if there is an error in
      -     * the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @see #setSendBufferSize
            * @see StandardSocketOptions#SO_SNDBUF
            * @since 1.2
      @@ -878,8 +890,8 @@ public int getSendBufferSize() throws SocketException {
            * @param size the size to which to set the receive buffer
            * size, in bytes. This value must be greater than 0.
            *
      -     * @throws    SocketException if there is an error in
      -     * the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @throws    IllegalArgumentException if the value is 0 or is
            * negative.
            * @see #getReceiveBufferSize()
      @@ -899,7 +911,8 @@ public void setReceiveBufferSize(int size) throws SocketException {
            * getOption(StandardSocketOptions.SO_RCVBUF)}.
            *
            * @return the value of the SO_RCVBUF option for this {@code DatagramSocket}
      -     * @throws    SocketException if there is an error in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @see #setReceiveBufferSize(int)
            * @see StandardSocketOptions#SO_RCVBUF
            * @since 1.2
      @@ -959,8 +972,8 @@ public void setReuseAddress(boolean on) throws SocketException {
            * getOption(StandardSocketOptions.SO_REUSEADDR)}.
            *
            * @return a {@code boolean} indicating whether or not SO_REUSEADDR is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @since   1.4
            * @see #setReuseAddress(boolean)
            * @see StandardSocketOptions#SO_REUSEADDR
      @@ -983,9 +996,8 @@ public boolean getReuseAddress() throws SocketException {
            * @param  on
            *         whether or not to have broadcast turned on.
            *
      -     * @throws  SocketException
      -     *          if there is an error in the underlying protocol, such as an UDP
      -     *          error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            *
            * @since 1.4
            * @see #getBroadcast()
      @@ -1003,8 +1015,8 @@ public void setBroadcast(boolean on) throws SocketException {
            * getOption(StandardSocketOptions.SO_BROADCAST)}.
            *
            * @return a {@code boolean} indicating whether or not SO_BROADCAST is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as an UDP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as an UDP error, or the socket is closed.
            * @since 1.4
            * @see #setBroadcast(boolean)
            * @see StandardSocketOptions#SO_BROADCAST
      @@ -1049,8 +1061,8 @@ public boolean getBroadcast() throws SocketException {
            * setOption(StandardSocketOptions.IP_TOS, tc)}.
            *
            * @param tc        an {@code int} value for the bitset.
      -     * @throws SocketException if there is an error setting the
      -     * traffic class or type-of-service
      +     * @throws SocketException if there is an error setting the traffic class or type-of-service,
      +     *         or the socket is closed.
            * @since 1.4
            * @see #getTrafficClass
            * @see StandardSocketOptions#IP_TOS
      @@ -1074,8 +1086,8 @@ public void setTrafficClass(int tc) throws SocketException {
            * getOption(StandardSocketOptions.IP_TOS)}.
            *
            * @return the traffic class or type-of-service already set
      -     * @throws SocketException if there is an error obtaining the
      -     * traffic class or type-of-service value.
      +     * @throws SocketException if there is an error obtaining the traffic class
      +     *         or type-of-service value, or the socket is closed.
            * @since 1.4
            * @see #setTrafficClass(int)
            * @see StandardSocketOptions#IP_TOS
      @@ -1092,6 +1104,9 @@ public int getTrafficClass() throws SocketException {
            *
            * <p> If this socket has an associated channel then the channel is closed
            * as well.
      +     *
      +     * <p> Once closed, several of the methods defined by this class will throw
      +     * an exception if invoked on the closed socket.
            */
           public void close() {
               delegate().close();
      @@ -1299,7 +1314,7 @@ public Set<SocketOption<?>> supportedOptions() {
            *         datagram packets, or {@code null}.
            * @throws IOException if there is an error joining, or when the address
            *         is not a multicast address, or the platform does not support
      -     *         multicasting
      +     *         multicasting, or the socket is closed
            * @throws SecurityException if a security manager exists and its
            *         {@code checkMulticast} method doesn't allow the join.
            * @throws IllegalArgumentException if mcastaddr is {@code null} or is a
      @@ -1343,7 +1358,7 @@ public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
            *         is unspecified: any interface may be selected or the operation
            *         may fail with a {@code SocketException}.
            * @throws IOException if there is an error leaving or when the address
      -     *         is not a multicast address.
      +     *         is not a multicast address, or the socket is closed.
            * @throws SecurityException if a security manager exists and its
            *         {@code checkMulticast} method doesn't allow the operation.
            * @throws IllegalArgumentException if mcastaddr is {@code null} or is a
      diff --git a/src/java.base/share/classes/java/net/MulticastSocket.java b/src/java.base/share/classes/java/net/MulticastSocket.java
      index 9a9d57118c0f1..46757a6b4077e 100644
      --- a/src/java.base/share/classes/java/net/MulticastSocket.java
      +++ b/src/java.base/share/classes/java/net/MulticastSocket.java
      @@ -221,7 +221,7 @@ public MulticastSocket(SocketAddress bindaddr) throws IOException {
            *
            * @param      ttl the time-to-live
            * @throws     IOException if an I/O exception occurs
      -     *             while setting the default time-to-live value
      +     *             while setting the default time-to-live value, or the socket is closed.
            * @deprecated use the {@link #setTimeToLive(int)} method instead, which uses
            *             <b>int</b> instead of <b>byte</b> as the type for ttl.
            * @see #getTTL()
      @@ -250,7 +250,7 @@ public void setTTL(byte ttl) throws IOException {
            *
            * @throws  IOException
            *          if an I/O exception occurs while setting the
      -     *          default time-to-live value
      +     *          default time-to-live value, or the socket is closed.
            *
            * @see #getTimeToLive()
            * @see StandardSocketOptions#IP_MULTICAST_TTL
      @@ -265,7 +265,7 @@ public void setTimeToLive(int ttl) throws IOException {
            * the socket.
            *
            * @throws    IOException if an I/O exception occurs
      -     * while getting the default time-to-live value
      +     *            while getting the default time-to-live value, or the socket is closed.
            * @return the default time-to-live value
            * @deprecated use the {@link #getTimeToLive()} method instead,
            * which returns an <b>int</b> instead of a <b>byte</b>.
      @@ -285,7 +285,7 @@ public byte getTTL() throws IOException {
            * getOption(StandardSocketOptions.IP_MULTICAST_TTL)}.
            *
            * @throws    IOException if an I/O exception occurs while
      -     * getting the default time-to-live value
      +     *            getting the default time-to-live value, or the socket is closed.
            * @return the default time-to-live value
            * @see #setTimeToLive(int)
            * @see StandardSocketOptions#IP_MULTICAST_TTL
      @@ -311,7 +311,7 @@ public int getTimeToLive() throws IOException {
            * @param      mcastaddr is the multicast address to join
            * @throws     IOException if there is an error joining,
            *             or when the address is not a multicast address,
      -     *             or the platform does not support multicasting
      +     *             or the platform does not support multicasting, or the socket is closed.
            * @throws     SecurityException if a security manager exists and its
            *             {@code checkMulticast} method doesn't allow the join.
            * @deprecated This method does not accept the network interface on
      @@ -339,7 +339,7 @@ public void joinGroup(InetAddress mcastaddr) throws IOException {
            *
            * @param      mcastaddr is the multicast address to leave
            * @throws     IOException if there is an error leaving
      -     *             or when the address is not a multicast address.
      +     *             or when the address is not a multicast address, or the socket is closed.
            * @throws     SecurityException if a security manager exists and its
            *             {@code checkMulticast} method doesn't allow the operation.
            * @deprecated This method does not accept the network interface on which
      @@ -393,7 +393,7 @@ public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
            *
            * @param      inf the InetAddress
            * @throws     SocketException if there is an error in
      -     *             the underlying protocol, such as a TCP error.
      +     *             the underlying protocol, such as a TCP error, or the socket is closed.
            * @deprecated The InetAddress may not uniquely identify
            *             the network interface. Use
            *             {@link #setNetworkInterface(NetworkInterface)} instead.
      @@ -413,7 +413,7 @@ public void setInterface(InetAddress inf) throws SocketException {
            *             or if no interface has been set, an {@code InetAddress}
            *             representing any local address.
            * @throws     SocketException if there is an error in the
      -     *             underlying protocol, such as a TCP error.
      +     *             underlying protocol, such as a TCP error, or the socket is closed.
            * @deprecated The network interface may not be uniquely identified by
            *             the InetAddress returned.
            *             Use {@link #getNetworkInterface()} instead.
      @@ -434,7 +434,7 @@ public InetAddress getInterface() throws SocketException {
            *
            * @param netIf the interface
            * @throws    SocketException if there is an error in
      -     * the underlying protocol, such as a TCP error.
      +     *            the underlying protocol, such as a TCP error, or the socket is closed.
            * @see #getNetworkInterface()
            * @see StandardSocketOptions#IP_MULTICAST_IF
            * @since 1.4
      @@ -454,7 +454,7 @@ public void setNetworkInterface(NetworkInterface netIf)
            * getOption(StandardSocketOptions.IP_MULTICAST_IF)}.
            *
            * @throws SocketException if there is an error in
      -     *         the underlying protocol, such as a TCP error.
      +     *         the underlying protocol, such as a TCP error, or the socket is closed.
            * @return The multicast {@code NetworkInterface} currently set. A placeholder
            *         NetworkInterface is returned when there is no interface set; it has
            *         a single InetAddress to represent any local address.
      @@ -476,7 +476,8 @@ public NetworkInterface getNetworkInterface() throws SocketException {
            * verify what loopback mode is set to should call
            * {@link #getLoopbackMode()}
            * @param      disable {@code true} to disable the LoopbackMode
      -     * @throws     SocketException if an error occurs while setting the value
      +     * @throws     SocketException if an error occurs while setting the value, or
      +     *             the socket is closed.
            * @since      1.4
            * @deprecated Use {@link #setOption(SocketOption, Object)} with
            *             {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP}
      @@ -493,7 +494,8 @@ public void setLoopbackMode(boolean disable) throws SocketException {
           /**
            * Get the setting for local loopback of multicast datagrams.
            *
      -     * @throws     SocketException if an error occurs while getting the value
      +     * @throws     SocketException if an error occurs while getting the value, or
      +     *             the socket is closed.
            * @return     true if the LoopbackMode has been disabled
            * @since      1.4
            * @deprecated Use {@link #getOption(SocketOption)} with
      @@ -534,8 +536,7 @@ public boolean getLoopbackMode() throws SocketException {
            * @param ttl optional time to live for multicast packet.
            * default ttl is 1.
            *
      -     * @throws     IOException is raised if an error occurs i.e
      -     *             error while setting ttl.
      +     * @throws     IOException  if an I/O error occurs, or the socket is closed.
            * @throws     SecurityException  if a security manager exists and its
            *             {@code checkMulticast} or {@code checkConnect}
            *             method doesn't allow the send.

            jpai Jaikiran Pai
            alanb Alan Bateman
            Alan Bateman, Daniel Fuchs
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: