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

    • b02
    • 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 ----------

              alanb Alan Bateman
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: