2

I currently am making a messaging application which I will also add encryption to later. I have a server which opens a socket and waits for clients to connect. Once client connects, it creates a new thread for that client. and then waits for messages etc.

The problem I am having is that when I try to send the public key exponent and modulus to the client, the Client is unable to use datainputstream(clientSocket.getInputStream()).readLine.

The sending of the exponent and Modulus happen on line 173 and 174.The receiving on the client side happens on line 125 and 136.

Server sending the data. os.println(modulusMap.get(requestName)); os.println(exponentMap.get(requestName));

Client attempting to write the data to a variable: pubModulusString = is.readLine().trim();
BigInteger pubModulus = new BigInteger(pubModulusString);
HashMap<String, BigInteger> modulusMap = new HashMap<String, BigInteger>(); modulusMap.put(message.substring(1), pubModulus);
String pubExponentString = is.readLine();

I have tested the sending of data as just a print stream and it is working perfectly. It is only when I try to read the data and save it into a variable that the problem occurs(line 125 and 136).

Majority of the time the readLine() reads the modulus as just blank, but sometimes it will successfully read it. I cannot find a pattern to when it is successful and when it is not.

What is also very weird is that I use the exact same code to send data from client to server. This can be seen on Client side line 89 and 91. And the server receives the data on lines 113 and 119.

Thank you for any help or ideas in advance.

Posted below is the full code for any 1 that is kind enough and has the time to run it.

Server:

    import java.io.*;
import java.math.*;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.*;



/*
 * A chat server that delivers public and private messages.
 */
public class MultiThreadChatServerSync {

  // The server socket.
  private static ServerSocket serverSocket = null;
  // The client socket.
  private static Socket clientSocket = null;

  // This chat server can accept up to maxClientsCount clients' connections.
  private static final int maxClientsCount = 10;
  private static final clientThread[] threads = new clientThread[maxClientsCount];

  public static void main(String args[]) {

    // The default port number.
    int portNumber = 2222;
    if (args.length < 1) {
      System.out.println("Usage: java MultiThreadChatServerSync <portNumber>\n"
          + "Now using port number=" + portNumber);
    } else {
      portNumber = Integer.valueOf(args[0]).intValue();
    }

    /*
     * Open a server socket on the portNumber (default 2222). Note that we can
     * not choose a port less than 1023 if we are not privileged users (root).
     */
    try {
      serverSocket = new ServerSocket(portNumber);
    } catch (IOException e) {
      System.out.println(e);
    }

    /*
     * Create a client socket for each connection and pass it to a new client
     * thread.
     */
    while (true) {
      try {
        clientSocket = serverSocket.accept();
        int i = 0;
        for (i = 0; i < maxClientsCount; i++) {
          if (threads[i] == null) {
            (threads[i] = new clientThread(clientSocket, threads)).start();
            break;
          }
        }
        if (i == maxClientsCount) {
          PrintStream os = new PrintStream(clientSocket.getOutputStream());
          os.println("Server too busy. Try later.");
          os.close();
          clientSocket.close();
        }
      } catch (IOException e) {
        System.out.println(e);
      }
    }
  }
}

/*
 * The chat client thread. This client thread opens the input and the output
 * streams for a particular client, ask the client's name, informs all the
 * clients connected to the server about the fact that a new client has joined
 * the chat room, and as long as it receive data, echos that data back to all
 * other clients. The thread broadcast the incoming messages to all clients and
 * routes the private message to the particular client. When a client leaves the
 * chat room this thread informs also all the clients about that and terminates.
 */
class clientThread extends Thread {

  private String clientName = null;
  private DataInputStream is = null;
  private BufferedReader inputLine = null;
  private PrintStream os = null;
  private Socket clientSocket = null;
  private final clientThread[] threads;
  private int maxClientsCount;

  public clientThread(Socket clientSocket, clientThread[] threads) {
    this.clientSocket = clientSocket;
    this.threads = threads;
    maxClientsCount = threads.length;
  }

  public void run() {
    int maxClientsCount = this.maxClientsCount;
    clientThread[] threads = this.threads;
    HashMap<String, BigInteger> modulusMap = new HashMap<String, BigInteger>();
    HashMap<String, BigInteger> exponentMap = new HashMap<String, BigInteger>();
    try {
      /*
       * Create input and output streams for this client.
       */
      is = new DataInputStream(clientSocket.getInputStream());
      os = new PrintStream(clientSocket.getOutputStream());
      inputLine = new BufferedReader (new InputStreamReader(System.in));
      String name;
      while (true) {
        os.println("Enter your name.");
        name = is.readLine().trim();

        String pubModulusString = is.readLine().trim();
        BigInteger pubModulus = new BigInteger(pubModulusString);


        modulusMap.put(name, pubModulus);

        String pubExponentString = is.readLine().trim();
        BigInteger pubExponent = new BigInteger(pubExponentString);


        exponentMap.put(name, pubExponent);


        if (name.indexOf('@') == -1) {
          break;
        } else {
          os.println("The name should not contain '@' character.");
        }
      }

      /* Welcome the new the client. */
      os.println("Welcome " + name
          + " to our chat room.\nTo leave enter /quit in a new line.");
      synchronized (this) {
        for (int i = 0; i < maxClientsCount; i++) {
          if (threads[i] != null && threads[i] == this) {
            clientName = "@" + name;
            break;
          }
        }
        for (int i = 0; i < maxClientsCount; i++) {
          if (threads[i] != null && threads[i] != this) {
            threads[i].os.println("*** A new user " + name
                + " entered the chat room !!! ***");
          }
        }








        }
      /* Start the conversation. */
      while (true) {
        String line = is.readLine();
        if (line.startsWith("/quit")) {
          break;
        }


        if (line.startsWith("!")){


        String requestName;
            requestName = line;
            requestName = requestName.substring(1);

            os.println(modulusMap.get(requestName));
            os.println(exponentMap.get(requestName));

        }
        else {



        /* If the message is private sent it to the given client. */
        if (line.startsWith("@")) {
          String[] words = line.split("\\s", 2);
          if (words.length > 1 && words[1] != null) {
            words[1] = words[1].trim();
            if (!words[1].isEmpty()) {
              synchronized (this) {
                for (int i = 0; i < maxClientsCount; i++) {
                  if (threads[i] != null && threads[i] != this
                      && threads[i].clientName != null
                      && threads[i].clientName.equals(words[0])) {
                    threads[i].os.println("<" + name + "> " + words[1]);
                    /*
                     * Echo this message to let the client know the private
                     * message was sent.
                     */
                    this.os.println(">" + name + "> " + words[1]);
                    break;
                  }
                }
              }
            }
          }
        } else {
          /* The message is public, broadcast it to all other clients. */
          synchronized (this) {
              this.os.println("Please select who you wish to message by typing '@username *Your Message*'");
          }
        }
        }
      }
      synchronized (this) {
        for (int i = 0; i < maxClientsCount; i++) {
          if (threads[i] != null && threads[i] != this
              && threads[i].clientName != null) {
            threads[i].os.println("*** The user " + name
                + " is leaving the chat room !!! ***");
          }
        }
      }
      os.println("*** Bye " + name + " ***");

      /*
       * Clean up. Set the current thread variable to null so that a new client
       * could be accepted by the server.
       */
      synchronized (this) {
        for (int i = 0; i < maxClientsCount; i++) {
          if (threads[i] == this) {
            threads[i] = null;
          }
        }
      }
      /*
       * Close the output stream, close the input stream, close the socket.
       */
      is.close();
      os.close();
      clientSocket.close();
    } catch (IOException e) {
    }
  }
}

Client

    import java.io.DataInputStream;
import java.io.*;
import java.math.*;
import java.math.BigInteger;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.security.*;
import java.security.spec.*;
import java.util.*;

import javax.crypto.*;



public class MultiThreadChatClient implements Runnable {

  // The client socket
  private static Socket clientSocket = null;
  // The output stream
  private static PrintStream os = null;
  // The input stream
  private static DataInputStream is = null;

  private static BufferedReader inputLine = null;
  private static boolean closed = false;


  private static final String PUBLIC_KEY_FILE = "Public.key"; 
  private static final String PRIVATE_KEY_FILE = "Private.key"; 

  public static void main(String[] args) {



    // The default port.
    int portNumber = 2222;
    // The default host.
String host = "192.168.0.16";

    if (args.length < 2) {
      System.out
          .println("Usage: java MultiThreadChatClient <host> <portNumber>\n"
              + "Now using host=" + host + ", portNumber=" + portNumber);
    } else {
      host = args[0];
      portNumber = Integer.valueOf(args[1]).intValue();
    }

    /*
     * Open a socket on a given host and port. Open input and output streams.
     */
    try {
      clientSocket = new Socket(host, portNumber);
      inputLine = new BufferedReader(new InputStreamReader(System.in));
      os = new PrintStream(clientSocket.getOutputStream());
      is = new DataInputStream(clientSocket.getInputStream());
    } catch (UnknownHostException e) {
      System.err.println("Don't know about host " + host);
    } catch (IOException e) {
      System.err.println("Couldn't get I/O for the connection to the host "
          + host);
    }

    /*
     * If everything has been initialized then we want to write some data to the
     * socket we have opened a connection to on the port portNumber.
     */
    if (clientSocket != null && os != null && is != null) {
      try {

        /* Create a thread to read from the server. */
        new Thread(new MultiThreadChatClient()).start();

        String myName = inputLine.readLine();
        os.println(myName.trim());

        try { 
           KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 
           keyPairGenerator.initialize(2048); //1024 used for normal securities 
           KeyPair keyPair = keyPairGenerator.generateKeyPair(); 
           PublicKey publicKey = keyPair.getPublic(); 
           PrivateKey privateKey = keyPair.getPrivate(); 

           //Pullingout parameters which makes up Key 
           KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
           RSAPublicKeySpec rsaPubKeySpec = (RSAPublicKeySpec) keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); 
           RSAPrivateKeySpec rsaPrivKeySpec = (RSAPrivateKeySpec) keyFactory.getKeySpec(privateKey, RSAPrivateKeySpec.class); 
           os.println(rsaPubKeySpec.getModulus());
           System.out.println(rsaPubKeySpec.getModulus());
           os.println(rsaPubKeySpec.getPublicExponent()); 

           FileOutputStream fos = null; 
           ObjectOutputStream oos = null;

           fos = new FileOutputStream(PUBLIC_KEY_FILE); 
           oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 

           oos.writeObject(rsaPubKeySpec.getModulus());
           oos.writeObject(rsaPubKeySpec.getPublicExponent());

           oos.close();
           fos.close();

           fos = new FileOutputStream(PRIVATE_KEY_FILE); 
           oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 

           oos.writeObject(rsaPrivKeySpec.getModulus());
           oos.writeObject(rsaPrivKeySpec.getPrivateExponent());

           oos.close();
           fos.close();

          } catch (NoSuchAlgorithmException e) { 
           e.printStackTrace(); 
          }catch (InvalidKeySpecException e) { 
           e.printStackTrace(); 
          } 

        while (!closed) {
        String message = inputLine.readLine();
            if (message.startsWith("!")){
                os.println(message.trim());

                String pubModulusString = is.readLine().trim();


                BigInteger pubModulus = new BigInteger(pubModulusString);

                HashMap<String, BigInteger> modulusMap = new HashMap<String, BigInteger>();

                modulusMap.put(message.substring(1), pubModulus);


                String pubExponentString = is.readLine();
                BigInteger pubExponent = new BigInteger(pubExponentString);

                HashMap<String, BigInteger> exponentMap = new HashMap<String, BigInteger>();

                exponentMap.put(message.substring(1), pubExponent);


                System.out.println(modulusMap.get(message.substring(1)) + " Hi");
                System.out.println(exponentMap.get(message.substring(1)) + "asdk");

            }
            else{
                // INSERT ENCRYPTION ON "message" here
                os.println(message.trim());
            }




        }
        /*
         * Close the output stream, close the input stream, close the socket.
         */
        os.close();
        is.close();
        clientSocket.close();
      } catch (IOException e) {
        System.err.println("IOException:  " + e);
      }
    }
  }

  /*
   * Create a thread to read from the server. (non-Javadoc)
   *
   * @see java.lang.Runnable#run()
   */
  public void run() {
    /*
     * Keep on reading from the socket till we receive "Bye" from the
     * server. Once we received that then we want to break.
     */
    String responseLine;
    try {
      while ((responseLine = is.readLine()) != null) {
        System.out.println(responseLine);
        if (responseLine.indexOf("*** Bye") != -1)
          break;
      }
      closed = true;
    } catch (IOException e) {
      System.err.println("IOException:  " + e);
    }
  }

}
CLOO
  • 21
  • 3
  • Do you expect people to go through hundreds of lines of code? Maybe you could reduce this to a minimal example that illustrates the problem? – Kenster May 26 '14 at 12:57
  • Sorry about that, I was hoping some one was nice enough to pilot it to recreate the problem. I have listed the lines that are concerned. I do admit this is my first post. Thank you for taking the time to comment, I will edit the post with a more concise segment of the code – CLOO May 26 '14 at 13:00

2 Answers2

0

If readLine() returns a blank line, it is because the sender sent a blank line. If it returns null, the sender has closed the connection.

You're looking in the wrong place.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thank you for the quick reply ! Yes, I have read this piece of documentation before also, but the next line is not blank. Also the readLine() is not consistently returning a blank String. Every maybe 1/10 it will return what I am expecting it to return which is a String being sent over from the server. I am thinking it might be a concurrency problem ? I really do not know though. Any input will help ! I will keep trying to see if it is reading a Blank line – CLOO May 26 '14 at 12:58
  • I agree. It is a concurrency problem. Few if any of those fields should be static for example, certainly not the socket or the streams. The client socket should not be a field in the server class at all: it should be a field in the spawned Runnable that handles the client connection. – user207421 May 26 '14 at 23:18
-1

The method readLine of DataInputStream is deprecated. I don't know why you use it, normally if you use an IDE like eclipse you'll see this method crossed out.

You should use a BufferedReader instead as explained in the Java documentation itself, here is a link.

lyz
  • 548
  • 6
  • 16