package net.sf.nebulacards.comm;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import net.sf.nebulacards.comm.netpkt.JoinPkt;
import net.sf.nebulacards.main.NebulaUI;
/**
* Server for the serialization protocol.
*
* @author James Ranson
* @since 0.7
*/
public class Serv extends Thread {
public static final boolean verbose = true;
private JoinManager jm = null;
private ComManager cm;
private GameRunner gr;
public Serv(GameRunner _gr, ComManager _cm, int port) throws IOException {
gr = _gr;
cm = _cm;
jm = new JoinManager(port);
jm.setDaemon(true);
}
public void run() {
jm.start();
try {
gr.join(); /* play through the game */
} catch (InterruptedException e) {}
try {
jm.end(); // game is over; don't allow anyone to join
synchronized (cm) {
while (cm.howManyActive() > 0)
cm.wait();
}
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
return;
}
if (verbose)
System.out.println("Server finished.");
}
private void doJoin(Socket s) throws IOException {
s.setTcpNoDelay(true);
s.setSoTimeout(10000);
ObjectOutputStream oos;
ObjectInputStream ois;
try {
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
} catch (Exception e) {
if (verbose) {
System.err.println("Bad connection from " + s.getInetAddress());
e.printStackTrace(System.err);
}
s.close();
return;
}
boolean error = false;
String name = "";
JoinPkt pkt = null;
try {
pkt = (JoinPkt) ois.readObject();
} catch (InterruptedIOException e) {
if (verbose)
System.err.println("Timeout from " + s.getInetAddress());
error = true;
} catch (EOFException e) {
if (verbose)
System.err.println("Disconnection from " + s.getInetAddress());
error = true;
} catch (Exception e) {
if (verbose) {
System.err.println("Bad connection from " + s.getInetAddress());
e.printStackTrace(System.err);
}
error = true;
}
if (pkt != null
&& (((name = ((JoinPkt) pkt).getName()) != null && (name
.length() < 1 || name.length() > 100)) || name == null)) {
if (verbose)
System.err.println("Improper name from " + s.getInetAddress());
error = true;
}
if (error) {
try {
ois.close();
oos.close();
} finally {
s.close();
}
} else {
SerializationUI sui = new SerializationUI(s, ois, oos, -1);
synchronized (cm) {
int where = cm.add(sui);
gr.setName(where, name);
if (verbose) {
System.out
.println(gr.getName(where)
+ " is joining the game from "
+ s.getInetAddress());
}
gr.broadcastTable();
gr.reconnect(where);
cm.notifyAll();
}
}
synchronized (this) {
notifyAll();
}
}
protected final void doBoot(int who, String why) {
if (verbose)
System.out.println("Initiating boot of " + who + " because " + why);
cm.getCommunicator(who).booted(why);
removePlayer(who);
gr.broadcastTable();
}
private void removePlayer(int w) {
synchronized (cm) {
gr.setName(w, "");
cm.remove(w);
cm.notifyAll();
}
if (verbose)
System.out.println("Server: Players remaining: "
+ cm.howManyActive());
synchronized (this) {
notifyAll();
}
}
// returns how many players are connected
public int howMany() {
return cm.howManyActive();
}
public String[] getNames() {
String[] names = new String[4];
for (int i = 0; i < names.length; i++)
names[i] = gr.getName(i);
return names;
}
public void tellBoot(int who, String why) {
doBoot(who, why);
}
public int addLocalPlayer(NebulaUI target, String name) {
int where;
synchronized (cm) {
where = cm.add(target);
if (where < 0)
return where;
gr.setName(where, name);
gr.reconnect(where);
cm.notifyAll();
}
gr.broadcastTable();
synchronized (this) {
notifyAll();
}
return where;
}
/**
* Inner member class to handle accepting new players.
*/
class JoinManager extends Thread {
ServerSocket sock = null;
int port;
boolean shouldStop = true;
public JoinManager(int _port) throws IOException {
port = _port;
sock = new ServerSocket(port);
sock.setSoTimeout(3000);
shouldStop = false;
}
public void end() {
shouldStop = true;
}
public void run() {
while (!shouldStop) {
Socket s;
try {
s = sock.accept();
doJoin(s);
} catch (InterruptedIOException e) {
} catch (IOException e) {
}
}
try {
sock.close();
} catch (Exception e) {
}
}
}
}