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

(sc) SocketChannel.close when thread blocked in read causes connection to be reset (win)

XMLWordPrintable

    • x86_64
    • windows

      A DESCRIPTION OF THE PROBLEM :
      Receiving connection reset error on client end when socket.close() is called.

      Steps
      - One thread runs through out application lifetime, whose purpose is to accept the incoming socket connection. (similar code gist as ServerThread.class attached)
      - After accepting the socket connection a new thread is created and handed over with the accepted socket. The new thread uses the socket input and output stream to read and write data.
      - Some other thread can decide based on circumstances to terminate the socket using socket.close().

      When socket.close() is called:

      Java 11: On socket.close() call, sends RST packet to the client, thus connection reset error on client end.
      Java 8: On socket.close() call, sends FIN packet to the client, thus no issue observed on client end.

      Note: Please ignore the thread sleep and all sort of duppy code attached. Its just for issue reproduction purpose. The real application is a proxy kinda server which accepts connection and forwards data to some other connection. The other connection once done with data instructs to close the accepted connection.

      REGRESSION : Last worked in version 8

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the provided sample code(test case code) in Java 8 and Java 11 to see the connection reset error.
      Three class:
      ServerThread.class
      Client.class
      Main.class

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Connection reset error should not appear as there is no data to read
      ACTUAL -
      Connection reset error

      ---------- BEGIN SOURCE ----------
      // server thread class

      import java.net.*;
      import java.io.*;
      import java.nio.channels.SelectionKey;
      import java.nio.channels.Selector;
      import java.nio.channels.ServerSocketChannel;
      import java.nio.channels.SocketChannel;
      import java.nio.channels.spi.SelectorProvider;
      import java.util.Set;

      public class ServerThread extends Thread {

          private final int port;
          private Socket s = null;
          private InputStream in = null;

          // Constructor with port
          public ServerThread(int port) {
              this.port = port;
          }

          public Socket getSocket() {
              return this.s;
          }

          public void run() {

      // Starts server and accept connection
              try {
                  Selector socketSelector = SelectorProvider.provider().openSelector();
                  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                  serverSocketChannel.configureBlocking(false);

                  InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", port);
                  serverSocketChannel.socket().bind(inetSocketAddress);

                  serverSocketChannel.register(socketSelector, SelectionKey.OP_ACCEPT);

                  socketSelector.select();
                  Set<SelectionKey> selectedKeys = socketSelector.selectedKeys();

                  for (SelectionKey selectionKey : selectedKeys) {
                      if (selectionKey.isAcceptable()) {
                          ServerSocketChannel sSC =
                                  (ServerSocketChannel) selectionKey.channel();

      // Accept the connection
                          SocketChannel socketChannel = sSC.accept();
                          s = socketChannel.socket();
                          System.out.println("Client accepted");

                          s.setKeepAlive(true);
                          s.setTcpNoDelay(true);

      // Takes input from the client socket
                          in = s.getInputStream();

                          int m = 0;
      // Reads message from client
                          while (m != -1) {
                              try {
                                  m = in.read(new byte[16]);
                                  System.out.println(m);
                              } catch (IOException i) {
                                  System.out.println("Got exception in server thread: " + i);
                                  break;
                              }
                          }
                          System.out.println("Closing connection");
                      }
                  }
                  selectedKeys.clear();
              } catch (IOException i) {
                  System.out.println("Got from server thread " + i);
              }
          }
      }
      --------------------------------------------------------------------------------------
      // client class
              import java.io .*;
              import java.net .*;

      public class Client {
          private Socket s = null;
          private InputStream in = null;

          // Constructor to put IP address and port
          public Client(String addr, int port) {
      // Establish a connection
              try {
                  s = new Socket(addr, port);
                  in = s.getInputStream();
                  System.out.println("Connected");
              } catch (UnknownHostException u) {
                  System.out.println(u);
                  return;
              } catch (IOException i) {
                  System.out.println(i);
                  return;
              }

      // String to read message from input
      //String m = "";
              int m = 0;
      // Keep reading until "Over" is input
              while (m != -1) {
                  try {
                      m = in.read(new byte[16]);
                      System.out.println(m);
                  } catch (IOException i) {
                      System.out.println("Got exception in client: " + i);
                      break;
                  }
              }

      // Close the connection
              try {
                  s.close();
              } catch (IOException i) {
                  System.out.println(i);
              }
          }
      }
      -------------------------------------------------------------------------------------
      // main class

              import java.io.IOException;

      public class Main {

          public static void main(String[] args) {
              ServerThread s = new ServerThread(5000);
              s.start();
              Thread t = new Thread(() -> {
                  try {
                      Thread.sleep(10000);
                      s.getSocket().close();
                  } catch (IOException e) {
                      System.out.println("Got IO exception");
                  } catch (InterruptedException e) {
                      System.out.println("Got InterruptedException");
                  }
              });
              t.start();

              Thread t1 = new Thread(() -> {
                  try {
                      Thread.sleep(5000);
                      Client c = new Client("127.0.0.1", 5000);
                  } catch (InterruptedException e) {
                      System.out.println("Got InterruptedException");
                  }
              });
              t1.start();


          }
      }
      ---------- END SOURCE ----------

            michaelm Michael McMahon
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: