2

I'm trying to build a simple TCP multithreaded client/server application. Whenever a Client (Socket) connects to the ServerSocket and send an Object (Message) that corresponds to the simple serializable class shown below, the server crashes when his ObjectInputStream tries to read from the client Socket getting a SocketExpection.

Message.java

package storageserver;

import java.io.Serializable;

public class Message implements Serializable {

    private static final long serialVersionUID = 27015L;

    public int ClientStatus; // 0 - NotLogged :::  1 - Logged
    public String Command;
    public String[] Commands;  

    public Message()
    {
        this.ClientStatus = 0;
        this.Command = null;
        this.Commands = null;
    }   

    public void createMessage(String msg)
    {
        this.Command = msg;
        this.Commands = msg.split("\\s+");
    }
}

StorageServer.java

package storageserver;
 // imports..


public class StorageServer {

    public static final int MAX_USERS = 250;

    ServerSocket myServerSocket;
    boolean serverOn = true;
    File workingDir;

    public StorageServer(int port, File dir) {

        try {
            InetAddress addr = InetAddress.getByName("192.168.1.73");

            myServerSocket = new ServerSocket(port, MAX_USERS, addr);
            workingDir = dir;
            if(!workingDir.exists())
                workingDir.mkdir();

            System.out.println("StorageServer created successfully.");

        } catch (IOException ex) {
            Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Could not create storage server on port 7000. Exiting."); 
            System.exit(-1); 
        }
    }

    public void listen()
    {
        System.out.println("Listening for connections...");
        while(serverOn)
        {
            try {
                //accepts incoming TCP connection
                Socket clientSocket = myServerSocket.accept();

                //starts new service thread to handle client requests in background
                new ClientHandleThread(clientSocket).start();
            }
            catch (IOException e)
            {
                System.out.println("Exception encountered on accept. Ignoring. Stack Trace :"); 
                e.printStackTrace();
            }
        }

        try {
            myServerSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class ClientHandleThread extends Thread {

        private Socket myClientSocket;
        private HashMap<String, Runnable> commandsMap;
        private Message messageToSend, messageToReceive;

        public ClientHandleThread() {
            super();
        }

        public ClientHandleThread(Socket myClientSocket) {
            this.myClientSocket = myClientSocket;
            this.messageToSend = new Message();
            this.messageToReceive = new Message();
        }

        private void help()
        {
            messageToSend.createMessage("Avaible commands:\n\n"
                + "exit                       -> Exits the App\n"
                + "stop                       -> Stops the server\n"
                + "dir                        -> Gets personal file's info in current server\n");
            messageToSend.ClientStatus = 0;
        }

        @Override
        public void run()
        {
            ObjectInputStream in = null; 
            ObjectOutputStream out = null;

            System.out.println("Accepted connection from "
                        +  myClientSocket.getInetAddress().getHostAddress()+ ":" + myClientSocket.getPort());

            try
            {        
                System.out.println("IN..");
                in = new ObjectInputStream(myClientSocket.getInputStream()); 
                out = new ObjectOutputStream(myClientSocket.getOutputStream()); 
                System.out.println("IN!");

                messageToReceive = (Message) in.readObject(); //exception here - Software caused connection abort: recv failed
                System.out.println("Client Says :" + messageToReceive.Command);

                out.writeObject(messageToSend);
                out.flush(); 

            } catch (IOException | ClassNotFoundException ex) {
                ex.printStackTrace();
                Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
            }
            finally
            {
                try
                {                    
                    in.close(); 
                    out.close(); 
                    myClientSocket.close(); 
                    System.out.println("...Stopped"); 
                } 
                catch(IOException e) 
                { 
                    e.printStackTrace(); 
                }
            }
        }

    }

}

Debug output

java.net.SocketException: Software caused connection abort: recv failed
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.net.SocketInputStream.read(SocketInputStream.java:223)
    at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2303)
    at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2596)
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2606)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1319)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at storageserver.StorageServer$ClientHandleThread.run(StorageServer.java:145)
nov 11, 2015 2:53:36 AM storageserver.StorageServer$ClientHandleThread run

What may be causing this exception ? I'm sure i do not close or reset the socket connection anywhere (client/server side).

EDIT:

Added client code below. Client gets an exception when trying to receive() a response from the server.

TCPService.java (Client)

package client;

//imports..

public class TCPService {

    private Socket clientSocket;


    public TCPService(String host, int port)
    {
        try {
            clientSocket = new Socket(InetAddress.getByName(host), port);
            clientSocket.setSoTimeout(5000);
        } catch (IOException ex) {
            System.err.println("Cant connect to Storage Server.\n" + ex);
            System.exit(-1);
        }

    }

    public Message receive()
    {
        try { 
            ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
            try {
                Message msg = (Message) in.readObject();

                if(msg instanceof Message)
                    return msg;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }      

        }   catch (IOException ex) {
            Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void send(Message msg)
    {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
            oos.writeObject(msg);
            oos.flush();
            oos.close();
        } catch (IOException ex) {
            Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    //Main
     public static void main(String[] args) throws IOException
    {        
        /* Service Variable Declaration */
        TCPService tcpService = new TCPService(args[0], args[1]);

        /* Other Variables */
        String buf = "";
        Scanner scanIn = new Scanner(System.in);
        Message msg = new Message();
        isTCPRunning = true;

        /* While-Loop for TCP Service */
        while (isTCPRunning)
        {
            System.out.print("[User@StorageServer] Insert command: ");
            buf = scanIn.nextLine();

            msg.createMessage(buf);

            scanIn.reset();

            tcpService.send(msg);

            msg = tcpService.receive(); //SocketException -> Socket Closed

            System.out.println("[StorageServer] " + msg.Command);

            tcpService.handleMessage(msg);
        }
}
user207421
  • 305,947
  • 44
  • 307
  • 483
xRed
  • 1,895
  • 6
  • 20
  • 36
  • I think we need to look at the client code, too. I'm not as sure as you are that the socket is not closed or reset. Also, are there any exceptions on the client side? – Warren Dew Nov 11 '15 at 05:38
  • Java serialization allows arbitrary code execution if commons-collections is on your classpath: http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/ – Alain O'Dea Nov 11 '15 at 11:28
  • @WarrenDew I added the client code. If you could take a look again i'de appreciate. – xRed Nov 11 '15 at 14:17
  • 1
    @AlainO'Dea I could not exactly understand the link you gave me. Could you give a short intro on that ? – xRed Nov 11 '15 at 14:23
  • 1
    @xRed in summary it says that someone who can create a certain set of serialized objects can compromise your server. The only condition is that you have a commons-collections JAR in your classpath. It's safer to use JSON, Protocol Buffers, or Thrift which are data only and built for untrusted data exchange. – Alain O'Dea Nov 11 '15 at 14:30
  • @AlainO'Dea I see, but i dont think its my message object that is causing the exception, am i wrong ? This is a app for academic purposes so the security is not yet that relevant. – xRed Nov 11 '15 at 18:54
  • 1
    @xRed absolutely valid. It's worth experimenting with serialization in a trust to trust environment for the convenience alone. This is not the cause of the exception. I just got out of surgery. I expect it's a sequence of method callso. the client breaking things. They have to match. I lool more deeply when I have a chance to rest. – Alain O'Dea Nov 11 '15 at 20:21
  • 1
    Immediately upon sending a message, the client closes the ObjectOutputStream. This closes the socket's output stream, which closes the socket. By the time the client tries to read from the input stream, the socket is already closed, thus the exception on the client side. This may also be causing the problem on the server side, since by the time the server is reading data, the TCP connection may have been closed. – Warren Dew Nov 12 '15 at 05:25
  • @WarrenDew That was the exact problem. Its solved now, thanks. – xRed Nov 12 '15 at 18:18
  • I guess I'll add my comment as an answer, then. – Warren Dew Nov 13 '15 at 02:05

1 Answers1

2

Immediately upon sending a message, the client closes the ObjectOutputStream. This closes the socket's output stream, which closes the socket. By the time the client tries to read from the input stream, the socket is already closed, thus the exception on the client side. This may also be causing the problem on the server side, since by the time the server is reading data, the TCP connection may have been closed.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44