scp-app

git clone git://git.codymlewis.com/scp-app.git
Log | Files | Refs | LICENSE

ChatServer.java (6843B)


      1 import java.io.BufferedReader;
      2 import java.io.PrintWriter;
      3 import java.math.BigInteger;
      4 import java.io.InputStreamReader;
      5 import java.io.IOException;
      6 import java.net.ServerSocket;
      7 import java.net.Socket;
      8 import java.net.InetAddress;
      9 /**
     10  * ChatServer.java
     11  * A socket based full duplex chat server
     12  *
     13  * @author Cody Lewis
     14  * @since 2018-08-10
     15  */
     16 public class ChatServer extends Chat {
     17     public static final long serialVersionUID = 1L;
     18     private ServerSocket serverSocket;
     19     private String username;
     20     private String welcomeMessage;
     21     private static final int BACKLOG = 1; // Max length for queue of messages
     22     public ChatServer(String title) { super(title); }
     23     /**
     24      * The main thread
     25      * @param args command line arguments
     26      */
     27     public static void main(String args[]) {
     28         ChatServer cs = new ChatServer("SCP Server");
     29         int exitVal = cs.run(args);
     30         System.exit(exitVal);
     31     }
     32     /**
     33      * The main flow of the program
     34      * @param args The arguments sent in with the program
     35      * @return an end status int
     36      */
     37     public int run(String args[]) {
     38         try {
     39             address = args.length > 0 ? InetAddress.getByName(args[0]) : InetAddress.getLocalHost();
     40             port = args.length > 1 ? Integer.parseInt(args[1]) : 3400;
     41             if(port < 1024) {
     42                 throw new SCPException("Using a port number 1023 or lower may interrupt system operations");
     43             }
     44             welcomeMessage = args.length > 2 ? args[2] : "Welcome to SCP";
     45             msgArea.append(String.format("Starting server on %s:%d\n", address.getHostAddress(), port));
     46             startSocket();
     47             msgArea.append("Started server\n");
     48             while(true) {
     49                 hostConnection();
     50                 disconnect = false;
     51                 isRecieving = true;
     52             }
     53         } catch(SCPException SCPe) {
     54             System.err.println("Error: " + SCPe.getMessage());
     55             return errorCodes.SCPERROR.value();
     56         } catch(IOException ioe)  {
     57             System.err.println("Error: " + ioe.getMessage());
     58             return errorCodes.IOERROR.value();
     59         }
     60     }
     61     /**
     62      * Host a client connection
     63      */
     64     private void hostConnection() throws SCPException, IOException {
     65         try {
     66             msgArea.append("Waiting for client to connect\n");
     67             acceptClient();
     68             msgArea.append("Client successfully connected\n");
     69             msgArea.append("Exchanging Keys\n");
     70             keyExchange();
     71             msgArea.append("Waiting for client to SCP connect\n");
     72             username = clientConnect();
     73             username = username.substring(1, username.length() - 1); // remove quotes
     74             otherUsername = username;
     75             if(username == "") { // Can't have a blank username anyway
     76                 cliSocket.close();
     77                 msgArea.append("Rejected client for time differential greater than 5, trying again");
     78             } else {
     79                 SCPAccept();
     80                 if(acknowledged()) {
     81                     msgArea.append(String.format("User %s has connected to SCP\n\n", username));
     82                     String message = welcomeMessage + "\n"; // send welcome message + chat rules to client
     83                     String[] encryptedMessage = AES.encrypt(sessionKey.toByteArray(), message);
     84                     for(String em : encryptedMessage) {
     85                         msgArea.append("Waiting for message to send...\n");
     86                         out.println(SCP.message(address.getHostAddress(), port, em));
     87                     }
     88                     msgArea.append("Message Sent: " + message + "\n");
     89                     while(!disconnect) {
     90                         messageLoop();
     91                         while(recvMsg.isAlive() || !disconnect);
     92                     }
     93                 }
     94             }
     95         } catch(NullPointerException npe) {
     96             msgArea.append("\nError: unexpected cut-off from client, looking for new client\n");
     97         } catch(Exception e) {
     98             msgArea.append("\nError: " + e.getMessage() + "\n");
     99         }
    100     }
    101     /**
    102      * Start a server socket
    103      * @param hostAddress The ip address for the host server
    104      * @param port The port to run the server on
    105      * @return True on successful start
    106      */
    107     private boolean startSocket() throws IOException {
    108         serverSocket = new ServerSocket(port, BACKLOG, address);
    109         return true;
    110     }
    111     /**
    112      * Accept a client into the server
    113      * @return True on client connection
    114      */
    115     private boolean acceptClient() throws IOException {
    116         cliSocket = serverSocket.accept();
    117         out = new PrintWriter(cliSocket.getOutputStream(), true);
    118         in = new BufferedReader(new InputStreamReader(cliSocket.getInputStream()));
    119         return true;
    120     }
    121     /**
    122      * Perform a diffie-hellman key exchange
    123      * @return true on completion
    124      */
    125     private boolean keyExchange() throws IOException {
    126         BigInteger prime = new BigInteger(in.readLine());
    127         BigInteger priKey = DH.genPrivateKey(prime);
    128         BigInteger pubKey = DH.genPublicKey(priKey, prime);
    129         sessionKey = DH.genSessionKey(new BigInteger(in.readLine()), priKey, prime);
    130         out.println(pubKey);
    131         return true;
    132     }
    133     /**
    134      * Recieve a SCP connection
    135      * @return Client's username
    136      */
    137     private String clientConnect() throws SCPException, IOException {
    138         String inLine, result = "", packet = "";
    139         while((inLine = in.readLine()).compareTo("SCP END") != 0) {
    140             packet += inLine + "\n";
    141         }
    142         try {
    143             result = SCP.parseConnect(packet, address.getHostAddress(), port);
    144         } catch(TimeDiffException tde) {
    145             reject(tde.getTimeDiff());
    146         }
    147         return result;
    148     }
    149     /**
    150      * Reject client for taking too long
    151      * @param timeDiff Difference in time of client request to server processing it
    152      */
    153     private void reject(int timeDiff) {
    154         out.println(SCP.reject(timeDiff, cliSocket.getLocalAddress().getHostAddress()));
    155     }
    156     /**
    157      * Send a SCP connect message to the client
    158      * @param username user specified name
    159      */
    160     private void SCPAccept() {
    161         out.println(SCP.accept(username, address.getHostAddress(), port));
    162     }
    163     /**
    164      * Check if the client has been acknowledged by the server
    165      */
    166     private boolean acknowledged() throws SCPException, IOException {
    167         String inLine, packet = "";
    168         while((inLine = in.readLine()).compareTo("SCP END") != 0) {
    169             packet += inLine + "\n";
    170         }
    171         boolean result = SCP.parseAcknowledge(packet, address.getHostAddress(), port, username);
    172         if(result) {
    173             return true;
    174         } else {
    175             throw new SCPException("SCP ACKNOWLEDGE", packet);
    176         }
    177     }
    178 }