Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: few edits for now

Recommendations discussed The recommendations suggested in the guideline CON13-J. Ensure that threads are stopped cleanly are insufficient to terminate a thread that is blocked on a blocking operation such as network or file input-output (IO). Consequently, threads and tasks should provide callers with an explicit termination mechanism to prevent denial of service vulnerabilities.

...

This noncompliant code example is similar to the preceding one but uses thread interruption to indicate that it is safe to shut down the thread. However, this is not useful because the thread is blocked on network IO as a consequence of using the readLine() method. Network IO is not responsive to thread interruption whne when a java.net.Socket is being used.

...

Compliant Solution (close socket connection)

This compliant solution closes resumes the socket connectionthread, by having the shutdown() method close the socket. As a result, the thread is bound to stop because the readLine() method will throw a SocketException when the socet is closed. Note that there is no way to keep the connection alive if the thread is to be cleanly halted immediately.

Code Block
bgColor#ccccff
public final class SocketReader implements Runnable {
  // ...
  
  public void readData() throws IOException {
    String string;
    try {
      while ((string = in.readLine()) != null) { 
        // Blocks until end of stream (null)
      }
    } finally {
      shutdown();
    }
  }
  
  public void shutdown() throws IOException {
    socket.close();
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    SocketReader reader = new SocketReader();
    Thread thread = new Thread(reader);
    thread.start();
    Thread.sleep(1000); 
    reader.shutdown();
  }
}

The finally block executes after shutdown() is called. Because the finally block also calls the shutdown() method, it is possible that the socket will be closed a second time, which has no effect.

A boolean flag can be used (as described earlier) if additional clean-up operations need to be performed. When performing asynchronous IO, a java.nio.channels.Selector may also be brought out of the blocked state by either invoking its close() or wakeup() method.

A boolean flag can be used (as shown earlier) if additional operations need to be performed. When supplementing the code with a flag, the shutdown() method should also set the flag to false so that the thread can cleanly exit from the while loop.

Compliant Solution (interruptible channel)

...

Code Block
bgColor#ccccff
public final class SocketReader implements Runnable {
  private final SocketChannel sc;
  private final Object lock = new Object();
  
  public SocketReader(String host, int port) throws IOException {
    sc = SocketChannel.open(new InetSocketAddress(host, port));    
  }
  
  public void run() {
    ByteBuffer buf = ByteBuffer.allocate(1024);
    try {
      synchronized (lock) {
        while (!Thread.interrupted()) {
          sc.read(buf);
          // ...
        }
      }
    } catch (IOException ie) {
      // Forward to handler
    }
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    SocketReader reader = new SocketReader("somehost", 25);
    Thread thread = new Thread(reader);
    thread.start();
    Thread.sleep(1000);
    thread.interrupt();
  }
}

This method technique interrupts the current thread, however, it only stops the thread because the code polls the interrupted flag using the method Thread.interrupted(), and shuts down the thread when it is interrupted. Using a SocketChannel ensures that the condition in the while loop is tested as soon as an interruption is received, despite the read operation being a blocking operation. Invoking the interrupt() method of a thread that is blocked because of a java.nio.channels.Selector also causes the thread to awaken.

...