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

Several methods in java.net.Socket and ServerSocket do not specify behavior when already bound, connected or closed

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 24
    • core-libs
    • None
    • behavioral
    • minimal
    • The update to the API docs just specifies the already existing implementation in those methods. As such there won't be any behavioural change.
    • Java API
    • SE

      Summary

      Several methods in java.net.Socket and java.net.ServerSocket will be updated to specify that they throw java.io.IOException or in some cases java.net.SocketException.

      Problem

      java.net.Socket and java.net.ServerSocket classes expose APIs to user applications for dealing with sockets. In the case of Socket, it exposes methods to bind, connect and close sockets. The ServerSocket exposes methods to bind, accept and close sockets. Apart from these methods, both the classes have several other methods, many of which rely on the state of the socket. These methods are currently implemented to throw an IOException or a SocketException, if the socket isn't in the correct state. For example, a socket which has been closed (through the use of the close() method) will throw an IOException when the connect() method is invoked. This current behaviour of throwing an exception based on the socket instance state isn't clearly specified in many of the methods.

      Solution

      The @throws clause in the methods of Socket and ServerSocket classes will be updated to specify the exception the implementation currently throws.

      Specification

      diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java
      index b3e570c858a62..cd353cabfbc27 100644
      
      --- a/src/java.base/share/classes/java/net/ServerSocket.java
      +++ b/src/java.base/share/classes/java/net/ServerSocket.java
      @@ -328,8 +328,8 @@ private SocketImpl getImpl() throws SocketException {
            * an ephemeral port and a valid local address to bind the socket.
            *
            * @param   endpoint        The IP address and port number to bind to.
      -     * @throws  IOException if the bind operation fails, or if the socket
      -     *                     is already bound.
      +     * @throws  IOException if the bind operation fails, the socket
      +     *                      is already bound or the socket is closed.
            * @throws  SecurityException       if a {@code SecurityManager} is present and
            * its {@code checkListen} method doesn't allow the operation.
            * @throws  IllegalArgumentException if endpoint is a
      @@ -357,8 +357,8 @@ public void bind(SocketAddress endpoint) throws IOException {
            * @param   endpoint        The IP address and port number to bind to.
            * @param   backlog         requested maximum length of the queue of
            *                          incoming connections.
      -     * @throws  IOException if the bind operation fails, or if the socket
      -     *                     is already bound.
      +     * @throws  IOException if the bind operation fails, the socket
      +     *                      is already bound or the socket is closed.
            * @throws  SecurityException       if a {@code SecurityManager} is present and
            * its {@code checkListen} method doesn't allow the operation.
            * @throws  IllegalArgumentException if endpoint is a
      @@ -518,7 +518,7 @@ public SocketAddress getLocalSocketAddress() {
            * client socket implementation factory}, if one has been set.
            *
            * @throws     IOException  if an I/O error occurs when waiting for a
      -     *               connection.
      +     *               connection, the socket is not bound or the socket is closed.
            * @throws     SecurityException  if a security manager exists and its
            *             {@code checkAccept} method doesn't allow the operation.
            * @throws     SocketTimeoutException if a timeout was previously set with setSoTimeout and
      @@ -806,8 +806,8 @@ public boolean isClosed() {
            * operation to have effect.
            *
            * @param timeout the specified timeout, in milliseconds
      -     * @throws  SocketException if there is an error in the underlying protocol,
      -     *          such as a TCP error
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @throws  IllegalArgumentException  if {@code timeout} is negative
            * @since   1.1
            * @see #getSoTimeout()
      @@ -824,7 +824,7 @@ public void setSoTimeout(int timeout) throws SocketException {
            * Retrieve setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
            * 0 returns implies that the option is disabled (i.e., timeout of infinity).
            * @return the {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} value
      -     * @throws    IOException if an I/O error occurs
      +     * @throws IOException if an I/O error occurs or the socket is closed.
            * @since   1.1
            * @see #setSoTimeout(int)
            */
      @@ -887,8 +887,8 @@ public void setReuseAddress(boolean on) throws SocketException {
            *
            * @return a {@code boolean} indicating whether or not
            *         {@code SO_REUSEADDR} is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol, such as a TCP error,
      +     *         or the socket is closed.
            * @since   1.4
            * @see #setReuseAddress(boolean)
            */
      @@ -1001,8 +1001,8 @@ public static synchronized void setSocketFactory(SocketImplFactory fac) throws I
            * requested value but the TCP receive window in sockets accepted from
            * this ServerSocket will be no larger than 64K bytes.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @param size the size to which to set the receive buffer
            * size. This value must be greater than 0.
      @@ -1029,8 +1029,8 @@ public void setReceiveBufferSize(int size) throws SocketException {
            * <p>Note, the value actually set in the accepted socket is determined by
            * calling {@link Socket#getReceiveBufferSize()}.
            * @return the value of the {@code SO_RCVBUF} option for this {@code Socket}.
      -     * @throws    SocketException if there is an error
      -     *            in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @see #setReceiveBufferSize(int)
            * @since 1.4
            */
      @@ -732,7 +732,8 @@ private void ensureCompatible(SocketImpl si) throws IOException {
            *
            * Any thread currently blocked in {@link #accept()} will throw
            * a {@link SocketException}.
      -     *
      +     * <p> Many methods in this class will throw an exception when invoked
      +     * on a closed socket.
            * <p> If this socket has an associated channel then the channel is closed
            * as well.
      
      diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java
      index 99a7bb6ca522e..69b1d598aef22 100644
      --- a/src/java.base/share/classes/java/net/Socket.java
      +++ b/src/java.base/share/classes/java/net/Socket.java
      @@ -683,7 +683,8 @@ void setConnected() {
            * </ol>
            *
            * @param   endpoint the {@code SocketAddress}
      -     * @throws  IOException if an error occurs during the connection
      +     * @throws  IOException if an error occurs during the connection, the socket
      +     *          is already connected or the socket is closed
            * @throws  java.nio.channels.IllegalBlockingModeException
            *          if this socket has an associated channel,
            *          and the channel is in non-blocking mode
      @@ -717,7 +718,8 @@ public void connect(SocketAddress endpoint) throws IOException {
            *
            * @param   endpoint the {@code SocketAddress}
            * @param   timeout  the timeout value to be used in milliseconds.
      -     * @throws  IOException if an error occurs during the connection
      +     * @throws  IOException if an error occurs during the connection, the socket
      +     *          is already connected or the socket is closed
            * @throws  SocketTimeoutException if timeout expires before connecting
            * @throws  java.nio.channels.IllegalBlockingModeException
            *          if this socket has an associated channel,
      @@ -780,8 +782,8 @@ public void connect(SocketAddress endpoint, int timeout) throws IOException {
            * an ephemeral port and a valid local address to bind the socket.
            *
            * @param   bindpoint the {@code SocketAddress} to bind to
      -     * @throws  IOException if the bind operation fails, or if the socket
      -     *                     is already bound.
      +     * @throws  IOException if the bind operation fails, the socket
      +     *          is already bound or the socket is closed.
            * @throws  IllegalArgumentException if bindpoint is a
            *          SocketAddress subclass not supported by this socket
            * @throws  SecurityException  if a security manager exists and its
      @@ -1174,8 +1176,8 @@ public void close() throws IOException {
            * will close the associated socket.
            *
            * @return     an output stream for writing bytes to this socket.
      -     * @throws     IOException  if an I/O error occurs when creating the
      -     *               output stream or if the socket is not connected.
      +     * @throws IOException  if an I/O error occurs when creating the
      +     *         output stream, the socket is not connected or the socket is closed.
            */
           public OutputStream getOutputStream() throws IOException {
               int s = state;
      @@ -1251,8 +1253,8 @@ public void close() throws IOException {
            * @param on {@code true} to enable {@code TCP_NODELAY},
            * {@code false} to disable.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @since   1.1
            *
      @@ -1269,8 +1271,8 @@ public void setTcpNoDelay(boolean on) throws SocketException {
            *
            * @return a {@code boolean} indicating whether or not
            *         {@code TCP_NODELAY} is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since   1.1
            * @see #setTcpNoDelay(boolean)
            */
      @@ -1289,9 +1291,9 @@ public boolean getTcpNoDelay() throws SocketException {
            *
            * @param on     whether or not to linger on.
            * @param linger how long to linger for, if on is true.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      -     * @throws    IllegalArgumentException if the linger value is negative.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
      +     * @throws  IllegalArgumentException if the linger value is negative.
            * @since 1.1
            * @see #getSoLinger()
            */
      @@ -1318,8 +1320,8 @@ public void setSoLinger(boolean on, int linger) throws SocketException {
            * The setting only affects socket close.
            *
            * @return the setting for {@code SO_LINGER}.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since   1.1
            * @see #setSoLinger(boolean, int)
            */
      @@ -1368,8 +1370,8 @@ public void sendUrgentData(int data) throws IOException {
            * @param on {@code true} to enable {@code SO_OOBINLINE},
            *           {@code false} to disable.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @since   1.4
            *
      @@ -1387,8 +1389,8 @@ public void setOOBInline(boolean on) throws SocketException {
            * @return a {@code boolean} indicating whether or not
            *         {@code SO_OOBINLINE} is enabled.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since   1.4
            * @see #setOOBInline(boolean)
            */
      @@ -1409,8 +1411,8 @@ public boolean getOOBInline() throws SocketException {
            *  to have effect.
            *
            * @param timeout the specified timeout, in milliseconds.
      -     * @throws  SocketException if there is an error in the underlying protocol,
      -     *          such as a TCP error
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @throws  IllegalArgumentException if {@code timeout} is negative
            * @since   1.1
            * @see #getSoTimeout()
      @@ -1428,8 +1430,8 @@ public void setSoTimeout(int timeout) throws SocketException {
            * 0 returns implies that the option is disabled (i.e., timeout of infinity).
            *
            * @return the setting for {@code SO_TIMEOUT}
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @since   1.1
            * @see #setSoTimeout(int)
      @@ -1455,14 +1457,12 @@ public int getSoTimeout() throws SocketException {
            * <p>Because {@code SO_SNDBUF} is a hint, applications that want to verify
            * what size the buffers were set to should call {@link #getSendBufferSize()}.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      -     *
            * @param size the size to which to set the send buffer
            * size. This value must be greater than 0.
            *
      -     * @throws    IllegalArgumentException if the
      -     * value is 0 or is negative.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
      +     * @throws  IllegalArgumentException if the value is 0 or is negative.
            *
            * @see #getSendBufferSize()
            * @since 1.2
      @@ -1481,8 +1481,8 @@ public void setSendBufferSize(int size) throws SocketException {
            * for output on this {@code Socket}.
            * @return the value of the {@code SO_SNDBUF} option for this {@code Socket}.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @see #setSendBufferSize(int)
            * @since 1.2
      @@ -1529,8 +1529,8 @@ public int getSendBufferSize() throws SocketException {
            * @throws    IllegalArgumentException if the value is 0 or is
            * negative.
            *
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            *
            * @see #getReceiveBufferSize()
            * @see ServerSocket#setReceiveBufferSize(int)
      @@ -1550,8 +1550,8 @@ public void setReceiveBufferSize(int size) throws SocketException {
            * for input on this {@code Socket}.
            *
            * @return the value of the {@code SO_RCVBUF} option for this {@code Socket}.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @see #setReceiveBufferSize(int)
            * @since 1.2
            */
      @@ -1570,8 +1570,8 @@ public int getReceiveBufferSize() throws SocketException {
            * Enable/disable {@link StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE}.
            *
            * @param on  whether or not to have socket keep alive turned on.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since 1.3
            * @see #getKeepAlive()
            */
      @@ -1586,8 +1586,8 @@ public void setKeepAlive(boolean on) throws SocketException {
            *
            * @return a {@code boolean} indicating whether or not
            *         {@code SO_KEEPALIVE} is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since   1.3
            * @see #setKeepAlive(boolean)
            */
      @@ -1637,8 +1637,8 @@ public boolean getKeepAlive() throws SocketException {
            * would be placed into the sin6_flowinfo field of the IP header.
            *
            * @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
      @@ -1661,8 +1661,8 @@ public void setTrafficClass(int tc) throws SocketException {
            * set using the {@link #setTrafficClass(int)} method on this Socket.
            *
            * @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
      @@ -1715,8 +1715,8 @@ public void setReuseAddress(boolean on) throws SocketException {
            *
            * @return a {@code boolean} indicating whether or not
            *         {@code SO_REUSEADDR} is enabled.
      -     * @throws    SocketException if there is an error
      -     * in the underlying protocol, such as a TCP error.
      +     * @throws SocketException if there is an error in the underlying protocol,
      +     *         such as a TCP error, or the socket is closed.
            * @since   1.4
            * @see #setReuseAddress(boolean)
            */
      @@ -1767,8 +1767,8 @@ public void close() throws IOException {
            * socket, the stream's {@code available} method will return 0, and its
            * {@code read} methods will return {@code -1} (end of stream).
            *
      -     * @throws    IOException if an I/O error occurs when shutting down this
      -     * socket.
      +     * @throws IOException if an I/O error occurs when shutting down this socket, the
      +     *         socket is not connected or the socket is closed.
            *
            * @since 1.3
            * @see java.net.Socket#shutdownOutput()
      @@ -1797,8 +1797,8 @@ public void shutdownInput() throws IOException {
            * shutdownOutput() on the socket, the stream will throw
            * an IOException.
            *
      -     * @throws    IOException if an I/O error occurs when shutting down this
      -     * socket.
      +     * @throws IOException if an I/O error occurs when shutting down this socket, the socket
      +     *         is not connected or the socket is closed.
            *
            * @since 1.3
            * @see java.net.Socket#shutdownInput()
      @@ -1733,8 +1733,9 @@ public boolean getReuseAddress() throws SocketException {
            * will throw a {@link SocketException}.
            * <p>
            * Once a socket has been closed, it is not available for further networking
      -     * use (i.e. can't be reconnected or rebound). A new socket needs to be
      -     * created.
      +     * use (i.e. can't be reconnected or rebound) and many methods in this class
      +     * will throw an exception when invoked on a closed socket. A new socket needs
      +     * to be created.
            *
            * <p> Closing this socket will also close the socket's
            * {@link java.io.InputStream InputStream} and

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

              Created:
              Updated:
              Resolved: