Compare commits

..

10 Commits

Author SHA1 Message Date
Deathsbreed
e4b9d9553a Tell new users how to list possible commands. 2014-11-18 11:44:46 -06:00
Deathsbreed
d19c6dccde There is no COPYRIGHT file. 2014-11-18 11:40:30 -06:00
Deathsbreed
24a711e8c1 Getting ready for new version release. 2014-11-17 21:13:05 -06:00
Deathsbreed
f6f9511537 Moving client to another repo. 2014-11-17 21:02:39 -06:00
Deathsbreed
51f3d88a8e Ban uses IP (not the entire address). 2014-11-17 20:52:02 -06:00
Deathsbreed
bf2c69bb32 Ban needs a little bit of work, but almost functional. 2014-11-17 16:57:37 -06:00
Deathsbreed
b6b6c07841 Implementing ban. 2014-11-17 16:48:57 -06:00
Deathsbreed
376a626506 Server will not admit any clients whose IP is on the banned.txt list. 2014-11-17 11:56:50 -06:00
Deathsbreed
4b9f582fd0 Server reads from banned.txt file containing banned IPs. 2014-11-17 11:46:14 -06:00
Deathsbreed
b9540f162f Admin password is now stored. 2014-11-15 23:47:21 -06:00
6 changed files with 94 additions and 216 deletions

View File

@ -1,7 +1,6 @@
ConsoleChat ConsoleChat-Server
=========== ==================
This is the _server-side_ to the __ConsoleChat__ project. This code takes care of handling commands and sending the information to all the other clients connected.
This program was made as a personal project to learn Java network programming. The concept of it is rather simple, all it does is send messages to a server which, in turn, sends the message to everyone else (aside from some other commands added). Although the license is MIT, please consider also disclosing the source-code under an open-source license. It helps to give back to the community and help others just like this may have helped you.
### Compiling ### Compiling
To compile the source code, make sure you have JDK and Apache Ant installed. Then run the following command: To compile the source code, make sure you have JDK and Apache Ant installed. Then run the following command:

View File

@ -1,10 +1,9 @@
<project name="ConsoleChat" basedir="." default="main" > <project name="ConsoleChat-Server" basedir="." default="main" >
<property name="src.dir" value="src" /> <property name="src.dir" value="src" />
<property name="bin.dir" value="bin" /> <property name="bin.dir" value="bin" />
<property name="classes.dir" value="${bin.dir}/classes" /> <property name="classes.dir" value="${bin.dir}/classes" />
<property name="jar.dir" value="${bin.dir}/jar" /> <property name="jar.dir" value="${bin.dir}/jar" />
<property name="main-class-client" value="consolechat.client.Client" /> <property name="main-class" value="consolechat.server.Server" />
<property name="main-class-server" value="consolechat.server.Server" />
<target name="clean" > <target name="clean" >
<delete dir="bin" /> <delete dir="bin" />
@ -17,14 +16,9 @@
<target name="jar" depends="compile" > <target name="jar" depends="compile" >
<mkdir dir="${jar.dir}" /> <mkdir dir="${jar.dir}" />
<jar destfile="${jar.dir}/${ant.project.name}-client.jar" basedir="${classes.dir}" > <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" >
<manifest> <manifest>
<attribute name="Main-Class" value="${main-class-client}" /> <attribute name="Main-Class" value="${main-class}" />
</manifest>
</jar>
<jar destfile="${jar.dir}/${ant.project.name}-server.jar" basedir="${classes.dir}" >
<manifest>
<attribute name="Main-Class" value="${main-class-server}" />
</manifest> </manifest>
</jar> </jar>
</target> </target>

View File

@ -1,116 +0,0 @@
package consolechat.client;
import java.net.*;
import java.io.*;
import java.lang.*;
/**
* @author Nicolás A. Ortega
* @copyright Nicolás A. Ortega
* @license MIT
* @year 2014
*
*/
public class Client implements Runnable {
private String version = "v1.0.1";
private Socket socket = null;
private ClientThread cThread = null;
private DataOutputStream streamOut = null;
private BufferedReader console = null;
private Thread thread = null;
public static void main(String[] args) {
if(args.length != 2) {
System.out.println("Usage: consolechat-client [server] [port]");
} else {
new Client(args[0], Integer.parseInt(args[1]));
}
}
// Constructor method
public Client(String server, int port) {
System.out.println("ConsoleChat client " + version + " Copyright (C) 2014 Nicolás A. Ortega\n" +
"This program comes with ABSOLUTELY NO WARRANTY; details in WARRANTY file.\n" +
"This is free software, and you are welcome to redistribute it\n" +
"under certain conditions; details in LICENSE file.\n");
try {
// Create a new socket connection
System.out.println("Connecting to server...");
socket = new Socket(server, port);
System.out.println("Connected!");
start();
} catch(UnknownHostException uhe) {
System.out.println("Host unknown: " + uhe.getMessage());
} catch(IOException e) {
System.out.println("Unknown exception: " + e.getMessage());
}
}
// The run method containing the main loop
public void run() {
String uinput;
while(thread != null) {
try {
uinput = console.readLine();
if(uinput.equals("/clientVersion")) {
System.out.println(version);
} else {
streamOut.writeUTF(uinput);
streamOut.flush();
}
} catch(IOException e) {
System.out.println("Sending error: " + e.getMessage());
stop();
}
}
}
// Handle messages
public void handle(String msg) {
if(msg.equals("/quit")) {
System.out.println("Goodbye bye. Press RETURN to exit...");
stop();
} else {
System.out.println(msg);
if(msg.length() > 6 && msg.substring(0, 5).equals("Kick:")) {
stop();
}
}
}
// Open and start all necessary threads
private void start() throws IOException {
console = new BufferedReader(new InputStreamReader(System.in));
streamOut = new DataOutputStream(socket.getOutputStream());
if(thread == null) {
cThread = new ClientThread(this, socket);
thread = new Thread(this);
thread.start();
}
}
// Stop and close all necessary threads
public void stop() {
if(thread != null) {
thread.interrupt();
thread = null;
}
try {
if(console != null) { console.close(); }
if(streamOut != null) { streamOut.close(); }
if(socket != null) { socket.close(); }
} catch(IOException e) {
System.out.println("Error closing...");
}
try {
cThread.close();
} catch(IOException e) {
System.out.println("Error closing the thread: " + e);
}
cThread.interrupt();
}
}

View File

@ -1,58 +0,0 @@
package consolechat.client;
import java.io.*;
import java.net.*;
/**
* @author Nicolás A. Ortega
* @copyright Nicolás A. Ortega
* @license MIT
* @year 2014
*
* For details on the copyright, look at the COPYRIGHT file that came with
* this program.
*
*/
public class ClientThread extends Thread {
private Socket socket = null;
private Client client = null;
private DataInputStream streamIn = null;
private boolean run = false;
// Constructor
public ClientThread(Client _client, Socket _socket) {
client = _client;
socket = _socket;
open();
start();
}
// Open all necessary streams/threads
public void open() {
try {
streamIn = new DataInputStream(socket.getInputStream());
} catch(IOException e) {
System.out.println("Error getting input stream: " + e);
client.stop();
}
run = true;
}
// Close the streams
public void close() throws IOException {
if(streamIn != null) { streamIn.close(); }
run = false;
}
// The run method which will be called every frame
public void run() {
while(run) {
try {
client.handle(streamIn.readUTF());
} catch(IOException e) {
System.out.println("Listening error: " + e.getMessage());
client.stop();
}
}
}
}

View File

@ -10,17 +10,15 @@ import java.util.*;
* @license MIT * @license MIT
* @year 2014 * @year 2014
* *
* For details on the copyright, look at the COPYRIGHT file that came with
* this program.
*
*/ */
public class Server implements Runnable { public class Server implements Runnable {
private String version = "v1.0.1"; private String version = "v1.1";
private ArrayList<ServerThread> clients = new ArrayList<ServerThread>(); private ArrayList<ServerThread> clients = new ArrayList<ServerThread>();
private ServerSocket sSocket = null; private ServerSocket sSocket = null;
private Thread thread = null; private Thread thread = null;
private int clientCount = 0; private int clientCount = 0;
private String passwd = "admin"; private String passwd = "admin";
private ArrayList<String> banned = new ArrayList<String>();
public static void main(String[] args) { public static void main(String[] args) {
if(args.length != 1) { if(args.length != 1) {
@ -45,6 +43,27 @@ public class Server implements Runnable {
} catch(IOException e) { } catch(IOException e) {
System.out.println(e); System.out.println(e);
} }
// Read admin password
try {
BufferedReader passwdbuffer = new BufferedReader(new FileReader("adminpasswd.txt"));
try {
passwd = passwdbuffer.readLine();
} catch(IOException ioe) {
System.out.println("Error reading from adminpassword.txt.");
}
} catch(FileNotFoundException fnfe) { System.out.println("No adminpasswd.txt file."); }
// Read banned list
try {
String bannedIP;
BufferedReader banbuffer = new BufferedReader(new FileReader("banned.txt"));
try {
while((bannedIP = banbuffer.readLine()) != null) {
banned.add(bannedIP);
}
} catch(IOException ioe) { System.out.println("Error while reading from banned.txt"); }
} catch(FileNotFoundException fnfe) { System.out.println("No banned.txt file."); }
} }
// The run method that will be called every frame // The run method that will be called every frame
@ -124,6 +143,14 @@ public class Server implements Runnable {
} else { } else {
clients.get(findClient(id)).send("You are not admin."); clients.get(findClient(id)).send("You are not admin.");
} }
} else if(input.length() > 11 && input.substring(0, 4).equals("/ban")) {
if(clients.get(findClient(id)).isAdmin()) {
int bID = Integer.parseInt(input.substring(5, 10));
String reason = input.substring(11);
ban(bID, reason);
} else {
clients.get(findClient(id)).send("You are not admin.");
}
} else if(input.length() > 10 && input.substring(0, 10).equals("/giveadmin")) { } else if(input.length() > 10 && input.substring(0, 10).equals("/giveadmin")) {
if(clients.get(findClient(id)).isAdmin()) { if(clients.get(findClient(id)).isAdmin()) {
int aID = Integer.parseInt(input.substring(11)); int aID = Integer.parseInt(input.substring(11));
@ -144,10 +171,25 @@ public class Server implements Runnable {
} }
} }
// Ban a client
public void ban(int id, String reason) {
int pos = findClient(id);
if(pos < 0) return;
String clientAddress = clients.get(pos).getSocket().getRemoteSocketAddress().toString();
String clientIP = clientAddress.substring(1, clientAddress.indexOf(':'));
try {
PrintWriter banwriter = new PrintWriter(new BufferedWriter(new FileWriter("banned.txt", true)));
banwriter.println(clientIP);
banwriter.close();
} catch(IOException ioe) { System.out.println("Error printing client IP '" + clientIP + "' to banned.txt ."); }
clients.get(pos).send("You have been banned from this server.\nReason: " + reason);
remove(id);
}
// Remove a client // Remove a client
public synchronized void remove(int id) { public synchronized void remove(int id) {
int pos = findClient(id); int pos = findClient(id);
if(pos >= 0) { if(pos < 0) return;
ServerThread toTerminate = clients.get(pos); ServerThread toTerminate = clients.get(pos);
System.out.println("Remove client thread: " + id + " at " + pos); System.out.println("Remove client thread: " + id + " at " + pos);
try { try {
@ -164,13 +206,20 @@ public class Server implements Runnable {
} }
toTerminate.interrupt(); toTerminate.interrupt();
} }
}
// Add a new client // Add a new client
public void addThread(Socket socket) { public void addThread(Socket socket) {
// If IP is banned to not admit!
String clientAddress = socket.getRemoteSocketAddress().toString();
String clientIP = clientAddress.substring(1, clientAddress.indexOf(':'));
for(int i = 0; i < banned.size(); i++) {
if(clientIP.equals(banned.get(i))) return;
}
// Otherwise add them
clients.add(new ServerThread(this, socket)); clients.add(new ServerThread(this, socket));
try { try {
clients.get(clientCount).open(); clients.get(clientCount).open();
clients.get(clientCount).send("Use /help for a list of commands.\n");
clients.get(clientCount).start(); clients.get(clientCount).start();
clientCount++; clientCount++;
} catch(IOException e) { } catch(IOException e) {
@ -182,5 +231,16 @@ public class Server implements Runnable {
public String getPasswd() { return passwd; } public String getPasswd() { return passwd; }
// Setter methods // Setter methods
public void setPasswd(String npasswd) { this.passwd = npasswd; } public void setPasswd(String npasswd) {
this.passwd = npasswd;
try {
PrintWriter writer = new PrintWriter("adminpasswd.txt", "UTF-8");
writer.println(npasswd);
writer.close();
} catch(UnsupportedEncodingException uee) {
System.out.println("Error writing new password to adminpasswd.txt");
} catch(FileNotFoundException fnfe) {
System.out.println("Error writing new password to adminpasswd.txt");
}
}
} }

View File

@ -9,9 +9,6 @@ import java.io.*;
* @license MIT * @license MIT
* @year 2014 * @year 2014
* *
* For details on the copyright, look at the COPYRIGHT file that came with
* this program.
*
*/ */
public class ServerThread extends Thread { public class ServerThread extends Thread {
private Server server = null; private Server server = null;
@ -74,7 +71,8 @@ public class ServerThread extends Thread {
send("Admin commands:\n" + send("Admin commands:\n" +
" - /chgpasswd [newpasswd] -- Change the server admin password.\n" + " - /chgpasswd [newpasswd] -- Change the server admin password.\n" +
" - /giveadmin [id] -- Give another client admin as well.\n" + " - /giveadmin [id] -- Give another client admin as well.\n" +
" - /kick [id] [reason] -- Kick out a user and state a reason for the kick.\n"); " - /kick [id] [reason] -- Kick out a user and state a reason for the kick.\n" +
" - /ban [id] [reason] -- Ban a user from ever being able to connect to the server again.\n");
} }
} else if(command.length() > 6 && command.substring(0, 6).equals("/admin")) { } else if(command.length() > 6 && command.substring(0, 6).equals("/admin")) {
if(command.substring(7).equals(server.getPasswd())) { if(command.substring(7).equals(server.getPasswd())) {
@ -123,6 +121,7 @@ public class ServerThread extends Thread {
// Getter methods // Getter methods
public int getID() { return id; } public int getID() { return id; }
public Socket getSocket() { return socket; }
public String getUsername() { return username; } public String getUsername() { return username; }
public boolean isAdmin() { return admin; } public boolean isAdmin() { return admin; }