· 5 years ago · Nov 14, 2019, 08:18 PM
1
2// Multi-threaded Server program
3// File name: TCPServerMT.java
4// Programmer:
5
6import java.io.*;
7import java.net.*;
8import java.util.ArrayList;
9import java.util.concurrent.TimeUnit;
10
11public class jb_TCPServerMT {
12 private static ServerSocket servSock;
13
14 private static ArrayList<Socket> sockets = new ArrayList<Socket>();
15 private static ArrayList<jb_ClientObject> clients = new ArrayList<jb_ClientObject>();
16 private static File file = new File("jb_chat.txt");
17 public static int n;
18
19 public static int g;
20
21 // Determines port number from command line and calls run() to start running server
22 public static void main(String[] args) {
23 System.out.println("Opening port...\n");
24 try {
25
26 // Create a server object using optional command line arguments, defaulting to
27 // port number 20500 if no port is specified
28 int portNumber = 20500;
29 n = 128;
30 g = 33;
31
32 if (args.length != 0 && args[0].equals("-p")) {
33 portNumber = Integer.parseInt(args[1]);
34 }
35
36 for (int i = 0; i < args.length - 1; i++) {
37 if (args[i].equals("-n")) {
38 n = Integer.parseInt(args[i+1]);
39 }
40 if (args[i].equals("-g")) {
41 g = Integer.parseInt(args[i+1]);
42 }
43 if (args[i].equals("-p")) {
44 portNumber = Integer.parseInt(args[i + 1]);
45 }
46
47 i++;
48 }
49
50 servSock = new ServerSocket(portNumber);
51 } catch (IOException e) {
52 System.out.println("Unable to attach to port!");
53 System.exit(1);
54 }
55 // Create a broadcast thread and send it the chat file, list of clients, and
56 // list of messages so far
57 jb_Broadcaster broadcaster = new jb_Broadcaster(clients, file);
58 broadcaster.start();
59 do {
60 run(broadcaster);
61 } while (true);
62
63 }
64
65 private static void run(jb_Broadcaster bt) {
66 Socket link = null;
67
68 try {
69
70// Put the server into a waiting state and start the connection timer once a link is established
71 link = servSock.accept();
72
73
74// print local host name
75 String host = InetAddress.getLocalHost().getHostName();
76 System.out.println("Client has estabished a connection to " + host);
77
78// Create a thread to handle this connection and give it the socket, list of clients, list of messages, and chat file
79
80 jb_ClientSender sender = new jb_ClientSender(link, clients, file, bt, n, g);
81
82 // If the chat file exists and there are no clients, delete the chat file
83 if (file.exists() && sockets.size() == 0) {
84 file.delete();
85 }
86
87// start serving this connection
88 sender.start();
89
90 } catch (IOException e) {
91 e.printStackTrace();
92 }
93
94 }
95
96}
97
98//Broadcaster thread class to handle sending a message to all connected clients at once
99class jb_Broadcaster extends Thread {
100 File file;
101 ArrayList<jb_ClientObject> clients;
102
103 // Constructor for the thread object
104 jb_Broadcaster(ArrayList<jb_ClientObject> clients, File file) {
105
106 this.clients = clients;
107 this.file = file;
108 }
109
110 public static String crypt(String message, byte pad) {
111 byte[] messageBytes = message.getBytes();
112 message = "";
113 for (int i = 0; i < messageBytes.length; i++) {
114 messageBytes[i] = (byte) (messageBytes[i] ^ pad);
115 message = (message + (char) messageBytes[i]);
116 }
117 return message;
118 }
119
120 // Broadcasts message to each socket except for the client that sent it and
121 // write it to the file
122 public synchronized void broadcast(String message, Socket source) {
123
124 try {
125 PrintWriter fout = new PrintWriter(new FileOutputStream("jb_chat.txt", true));
126 fout.println(message);
127 fout.close();
128 } catch (Exception e) {
129 e.printStackTrace();
130 }
131
132 for (int i = 0; i < clients.size(); i++) {
133 if (!clients.get(i).getClient().equals(source)) {
134 try {
135 PrintWriter out = new PrintWriter(clients.get(i).getClient().getOutputStream(), true);
136 System.out.println("Broadcasting: " + message);
137 out.println(crypt(message, clients.get(i).getPad()));
138
139 } catch (IOException e) {
140 e.printStackTrace();
141 }
142 }
143 }
144
145 }
146
147 // Runs automatically when the thread is created, handles the chat file and the
148 // number of clients
149 public void run() {
150
151 }
152}
153//Client object to keep track of sockets and their corresponding secret key pad
154class jb_ClientObject{
155 private Socket client;
156 private byte pad;
157
158 public jb_ClientObject(Socket client, byte pad) {
159 this.client = client;
160 this.pad = pad;
161
162 }
163
164 public Socket getClient() {
165 return client;
166 }
167
168 public byte getPad() {
169 return pad;
170 }
171
172 public void setPad(byte pad) {
173 this.pad = pad;
174 }
175
176}
177
178//Handles the sending of data to the client
179class jb_ClientSender extends Thread {
180
181 //private ArrayList<Socket> sockets;
182 private ArrayList<jb_ClientObject> clients;
183 private Socket client;
184 private BufferedReader in;
185 private PrintWriter out;
186 private File file;
187 private String username;
188 private int numMessages;
189 private jb_Broadcaster bt;
190 private int n, g;
191 private byte pad;
192 private jb_ClientObject clientObj;
193 public jb_ClientSender(Socket s, ArrayList<jb_ClientObject> clients, File file, jb_Broadcaster bt, int n, int g) {
194 this.bt = bt;
195 numMessages = 0;
196 this.n = n;
197 this.g = g;
198 clientObj = new jb_ClientObject(s, (byte) 0);
199 client = s;
200 this.clients = clients;
201 this.file = file;
202
203 if (!file.exists()) {
204 file = new File("jb_chat.txt");
205 }
206
207 try {
208 in = new BufferedReader(new InputStreamReader(client.getInputStream()));
209 out = new PrintWriter(client.getOutputStream(), true);
210 } catch (IOException e) {
211 e.printStackTrace();
212 }
213 }
214 //Return a^b mod c
215 static int exponentMod(int a, int b, int c) {
216
217 // Base cases
218 if (a == 0)
219 return 0;
220 if (b == 0)
221 return 1;
222
223 // If B is even
224 long y;
225 if (b % 2 == 0) {
226 y = exponentMod(a, b / 2, c);
227 y = (y * y) % c;
228 }
229
230 // If B is odd
231 else {
232 y = a % c;
233 y = (y * exponentMod(a, b - 1, c) % c) % c;
234 }
235
236 return (int) ((y + c) % c);
237 }
238
239
240 public static String crypt(String message, byte pad) {
241 System.out.println("Attempting to crypt: "+message);
242 byte[] messageBytes = message.getBytes();
243 message = "";
244 for (int i = 0; i < messageBytes.length; i++) {
245 messageBytes[i] = (byte) (messageBytes[i] ^ pad);
246 message = (message + (char) messageBytes[i]);
247 }
248 return message;
249 }
250
251 public void run() {
252 long startTime = System.currentTimeMillis();
253
254 try {
255
256 file = new File("jb_chat.txt");
257 file.createNewFile();
258 if (!file.exists()) {
259 file = new File("jb_chat.txt");
260 }
261
262
263
264
265 //Diffie-Hellman Handshake
266 int gX, gY, x;
267 //Pick a random number between 100 and 200
268 x = (int)(Math.random() * ((200 - 100) + 1)) + 100;
269 //Send n to the client
270 out.println(n);
271 //Send g to the client
272 out.println(g);
273 //Send g^x mod n
274 gX = exponentMod(g, x, n);
275 out.println(gX);
276 //Read g^y mod n from the client
277 gY = Integer.parseInt(in.readLine());
278
279 int secretKey = exponentMod(gY, x, n);
280 pad = (byte) secretKey;
281 username = crypt(in.readLine(), pad);
282 System.out.println("****Client Info****");
283 System.out.println("Username: "+username);
284 System.out.println("n: "+n);
285 System.out.println("g: "+g);
286 System.out.println("Session Key: "+secretKey);
287 System.out.println("Byte pad: "+pad);
288 System.out.println();
289 clientObj.setPad(pad);
290
291 synchronized(clients){
292 clients.add(clientObj);
293 }
294
295 bt.broadcast("*****" + username + " has connected to the chat*****", client);
296
297 BufferedReader fin = new BufferedReader(new FileReader(file));
298
299 while (fin.readLine() != null)
300 numMessages++;
301 fin.close();
302 // Reset the BufferedReader to the start of the file
303 fin = new BufferedReader(new FileReader("jb_chat.txt"));
304
305 out.println(crypt(Integer.toString(numMessages), pad)); // send the length of the chat file to the client
306 String message = "";
307 for (int k = numMessages; k > 0; k--) {
308 // Send the contents of the file to the client
309 message = fin.readLine();
310 out.println(crypt(message, pad));
311 }
312 fin.close();// Close the file
313 //TODO figure out why this is null
314
315 message = "";
316 message = in.readLine();
317 message = crypt(message, pad);
318 while (!message.equals("DONE")) {
319 message = username + ": " + message;
320 numMessages++;
321 System.out.println(message);
322 bt.broadcast(message, client);
323
324 message = crypt(in.readLine(), pad);
325
326 }
327
328 // Send a report back and close the connection
329 out.println(crypt("Server received " + numMessages + " messages", pad)); // Send final r
330 long duration = System.currentTimeMillis() - startTime;
331
332 long hours = TimeUnit.MILLISECONDS.toHours(duration);
333 duration = duration - TimeUnit.HOURS.toMillis(hours);
334 long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
335 duration = duration - TimeUnit.MINUTES.toMillis(minutes);
336 long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
337 duration = duration - TimeUnit.SECONDS.toMillis(seconds);
338 String connectionTime = String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, duration);
339
340 out.println(crypt(("Connection Time: " + connectionTime), pad));
341
342 out.println(crypt("DONE", pad));// Signal to the client that the server is ready to send the final report
343
344
345 bt.broadcast("*****" + username + " has left the chat*****", client);
346
347 } catch (IOException e) {
348 e.printStackTrace();
349
350 }
351
352 clients.remove(clientObj);
353 if(clients.size() == 0) {
354 file.delete();
355 }
356 }
357
358}