-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathServer.java
434 lines (409 loc) · 16.7 KB
/
Server.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.security.*;
import java.nio.file.*;
/*
* The server that can be run both as a console application or a GUI
*/
public class Server {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the Client
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUI sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the server
private boolean keepGoing;
// maneja las claves mientras pasan por el servidor
private String recibiendo;
private PublicKey recibiendoclave;
/*
* server constructor that receive the port to listen to for connection as parameter
* in console
*/
public Server(int port) {
this(port, null);
}
public Server(int port, ServerGUI sg) {
// GUI or not
sg = null;
this.sg = sg;
// the port
this.port = port;
// to display hh:mm:ss
sdf = new SimpleDateFormat("HH:mm:ss");
// ArrayList for the Client list
al = new ArrayList<ClientThread>();
}
public void start() {
keepGoing = true;
/* create socket server and wait for connection requests */
try {
// the socket used by the server
ServerSocket serverSocket = new ServerSocket(port);
// infinite loop to wait for connections
while (keepGoing) {
// format message saying we are waiting
display("Server waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); // accept connection
// if I was asked to stop
if(!keepGoing)
break;
ClientThread t = new ClientThread(socket); // make a thread of it
al.add(t); // save it in the ArrayList
if(al.size()==1){
broadcast(new ChatMessage(ChatMessage.MESSAGE,"Eres el primero que chupi"));
}
if(al.size()>1){
String time = sdf.format(new Date());
String messageLf = time + " " + "No eres el primero que chupi" + "\n";
t.writeObject(new ChatMessage(ChatMessage.MESSAGE,messageLf));
//metodo sincronizador, tiene que esperar a las cosas
messageLf = time + " " + "Vas a mandarme tu clave publica" + "\n";
t.writeObject(new ChatMessage(ChatMessage.MESSAGE,messageLf));
t.runkey();
messageLf = time + " " + recibiendo + "\n";
al.get(0).writeObject(new ChatMessage(ChatMessage.KEY,recibiendoclave));
try {Thread.sleep(5000);} catch (InterruptedException e) {}
messageLf = time + " " + recibiendo + "\n";
t.writeObject(new ChatMessage(ChatMessage.MESSAGE,messageLf));
}
t.start();
}
// I was asked to stop
try {
serverSocket.close();
for(int i = 0; i < al.size(); ++i) {
ClientThread tc = al.get(i);
try {
tc.sInput.close();
tc.sOutput.close();
tc.socket.close();
}
catch(IOException ioE) {
// not much I can do
}
}
}
catch(Exception e) {
display("Exception closing the server and clients: " + e);
}
}
// something went bad
catch (IOException e) {
String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
display(msg);
}
}
/*
* For the GUI to stop the server
*/
protected void stop() {
keepGoing = false;
// connect to myself as Client to exit statement
// Socket socket = serverSocket.accept();
try {
new Socket("localhost", port);
} catch (Exception e) {
// nothing I can really do
}
}
/*
* Display an event (not a message) to the console or the GUI
*/
private void display(String msg) {
String time = sdf.format(new Date()) + " " + msg;
if (sg == null)
System.out.println(time);
else
sg.appendEvent(time + "\n");
}
/*
* to broadcast a message to all Clients
*/
private synchronized void broadcast(String message) { // este metodo manda todo a todos los usuarios
// add HH:mm:ss and \n to the message
String time = sdf.format(new Date());
String messageLf = time + " " + message + "\n"; //aqui esta el mensaje en sí
// display message on console or GUI
if (sg == null)
System.out.print(messageLf); //lo imprime en consola
else
sg.appendRoom(messageLf); // append in the room window
// we loop in reverse order in case we would have to remove a Client
// because it has disconnected
for (int i = al.size(); --i >= 0; ) {
ClientThread ct = al.get(i);
// try to write to the Client if it fails remove it from the list
if (!ct.writeMsg(messageLf)) {
al.remove(i);
display("Disconnected Client " + ct.username + " removed from list.");
}
}
}
private synchronized void broadcast(ChatMessage objeto) { // este metodo manda todo a todos los usuarios
// add HH:mm:ss and \n to the message
if(objeto.getType()==1){
String time = sdf.format(new Date());
String messageLf = time + " " + objeto.getMessage() + "\n";
objeto=new ChatMessage(ChatMessage.MESSAGE,messageLf);
if (sg == null)
System.out.print(messageLf); //lo imprime en consola
else
sg.appendRoom(messageLf); // append in the room window
}
for (int i = al.size(); --i >= 0; ) {
ClientThread ct = al.get(i);
if (!ct.writeObject(objeto)) {
al.remove(i);
display("Disconnected Client " + ct.username + " removed from list.");
}
}
}
// for a client who logoff using the LOGOUT message
synchronized void remove(int id) {
// scan the array list until we found the Id
for (int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
// found it
if (ct.id == id) {
al.remove(i);
return;
}
}
}
/*
* To run as a console application just open a console window and:
* > java Server
* > java Server portNumber
* If the port number is not specified 1500 is used
*/
public static void main(String[] args) {
// start server on port 1500 unless a PortNumber is specified
int portNumber = 1500;
switch (args.length) {
case 1:
try {
portNumber = Integer.parseInt(args[0]);
} catch (Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Server [portNumber]");
return;
}
case 0:
break;
default:
System.out.println("Usage is: > java Server [portNumber]");
return;
}
// create a server object and start it
Server server = new Server(portNumber);
server.start();
}
/**
* One instance of this thread will run for each client
*/
class ClientThread extends Thread {
// the socket where to listen/talk
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
// my unique id (easier for deconnection)
int id;
// the Username of the Client
String username;
// the only type of message a will receive
ChatMessage cm;
// the date I connect
String date;
boolean keyflag=false;
// Constructore
ClientThread(Socket socket) {
// a unique id
id = ++uniqueId;
this.socket = socket;
/* Creating both Data Stream */
System.out.println("Thread trying to create Object Input/Output Streams");
try {
// create output first
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read the username
username = (String) sInput.readObject();
display(username + " just connected.");
} catch (IOException e) {
display("Exception creating new Input/output Streams: " + e);
return;
}
// have to catch ClassNotFoundException
// but I read a String, I am sure it will work
catch (ClassNotFoundException e) {
}
date = new Date().toString() + "\n";
}
//hará una sola lectura del cliente para nosotros
private void runkey(){
try {
cm = (ChatMessage) sInput.readObject();
} catch (IOException e) {
display(username + " Exception reading Streams: " + e);
} catch (ClassNotFoundException e2) {
}
// the messaage part of the ChatMessage
String message = cm.getMessage();
if(message.equalsIgnoreCase("~0~")){
recibiendoclave=cm.getKey();
System.out.println("Tengo una clave publica de algun usuario y se la doy al primer usuario");
}
if(message.substring(0,3).equalsIgnoreCase("~1~")){
recibiendo=message;
System.out.println("Tengo una clave AES encriptada y se la doy a otro usuario");
}
}
// what will run forever
public void run() {
// to loop until LOGOUT
boolean keepGoing = true;
while (keepGoing) {
// read a String (which is an object)
try {
cm = (ChatMessage) sInput.readObject();
} catch (IOException e) {
display(username + " Exception reading Streams: " + e);
break;
} catch (ClassNotFoundException e2) {
break;
}
// the messaage part of the ChatMessage
String message = cm.getMessage();
byte[] archivo = cm.getContenido();
// Switch on the type of message receive
switch (cm.getType()) {
case ChatMessage.MESSAGE:
if(message.contains("~1~")){
recibiendo=message;
System.out.println("Tengo una clave AES encriptada y se la doy a otro usuario");
}
else{
broadcast(new ChatMessage(ChatMessage.MESSAGE,username + ": " + message));
}
break;
case ChatMessage.CIPHERMESSAGE:
System.out.println(message);
for (int i = al.size(); --i >= 0; ) {
ClientThread ct = al.get(i);
// try to write to the Client if it fails remove it from the list
if (!ct.writeObject(new ChatMessage(ChatMessage.CIPHERMESSAGE,message))) {
al.remove(i);
display("Disconnected Client " + ct.username + " removed from list.");
}
}
break;
case ChatMessage.LOGOUT:
display(username + " disconnected with a LOGOUT message.");
keepGoing = false;
break;
case ChatMessage.WHOISIN:
writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
// scan al the users connected
for (int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
writeMsg((i + 1) + ") " + ct.username + " since " + ct.date);
}
break;
case ChatMessage.FILE:
System.out.println("Transfiriendo un archivo");
broadcast(cm);
break;
}
}
// remove myself from the arrayList containing the list of the
// connected Clients
remove(id);
close();
}
// try to close everything
private void close() {
// try to close the connection
try {
if (sOutput != null) sOutput.close();
} catch (Exception e) {
}
try {
if (sInput != null) sInput.close();
} catch (Exception e) {
}
;
try {
if (socket != null) socket.close();
} catch (Exception e) {
}
}
/*
* Write a String to the Client output stream
*/
private boolean writeMsg(String msg) {
// if Client is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(msg);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending message to " + username);
display(e.toString());
}
return true;
}
/*
* Write a File to the Client output stream
*/
private boolean writeFile(byte[] msg) {
// if Client is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(msg);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending file to " + username);
display(e.toString());
}
return true;
}
/*
* Write a Object to the Client output stream
*/
private boolean writeObject(ChatMessage cm) {
// if Client is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(cm);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending file to " + username);
display(e.toString());
}
return true;
}
}
}