Merge branch 'issue47_disconnect_crash_rebranch' into 'develop'

Issue47 disconnect crash rebranch

Fix for all disconnection issues. Fix is not robust. Need consistent interface between disconnection of ServerToClientThreads and MainServerThread.

See merge request !66
This commit is contained in:
Alistair McIntyre
2017-08-17 14:55:45 +12:00
10 changed files with 232 additions and 158 deletions
@@ -429,7 +429,6 @@ public class GameState implements Runnable {
private void checkForLegProgression(ServerYacht yacht) {
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
CompoundMark currentMark = markOrder.getCurrentMark(currentMarkSeqID);
// System.out.println(yacht.getCurrentMarkSeqID());
Boolean hasProgressed;
if (currentMarkSeqID == 0) {
@@ -92,6 +92,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
try {
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.terminate();
}
serverSocket.close();
return;
} catch (IOException e) {
@@ -172,6 +175,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
thread.sendSetupMessages();
}
});
serverToClientThread.addDisconnectListener(this::clientDisconnected);
}
/**
@@ -181,11 +185,11 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
*/
@Override
public void clientDisconnected(Player player) {
try {
player.getSocket().close();
} catch (Exception e) {
serverLog("Cannot disconnect the socket for the disconnected player.", 0);
}
// try {
// player.getSocket().close();
// } catch (Exception e) {
// serverLog("Cannot disconnect the socket for the disconnected player.", 0);
// }
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
GameState.removeYacht(player.getYacht().getSourceId());
GameState.removePlayer(player);
@@ -193,11 +197,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) {
closedConnection = serverToClientThread;
} else {
} else if (GameState.getCurrentStage() != GameStages.RACING){
serverToClientThread.sendSetupMessages();
}
}
serverToClientThreads.remove(closedConnection);
closedConnection.terminate();
}
public void startGame() {
@@ -38,7 +38,7 @@ public class ServerListenThread implements Runnable {
}
public void run(){
while (true){
while (serverSocket != null && !serverSocket.isClosed()){
acceptConnection();
}
}
@@ -40,17 +40,20 @@ import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.ClientType;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RaceStatus;
import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.messages.RaceType;
import seng302.gameServer.messages.RegistrationResponseMessage;
import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.model.Player;
import seng302.model.ServerYacht;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator;
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
@@ -67,6 +70,12 @@ public class ServerToClientThread implements Runnable, Observer {
void notifyConnection ();
}
// TODO: 17/08/17 this is only temporary disconnects should be handled consistently
@FunctionalInterface
interface DisconnectListener {
void notifyDisconnect (Player player);
}
private Logger logger = LoggerFactory.getLogger(ServerToClientThread.class);
private Thread thread;
@@ -86,8 +95,10 @@ public class ServerToClientThread implements Runnable, Observer {
private XMLGenerator xml;
private List<ConnectionListener> connectionListeners = new ArrayList<>();
private DisconnectListener disconnectListener;
private ServerYacht yacht;
private Player player;
public ServerToClientThread(Socket socket) {
this.socket = socket;
@@ -134,8 +145,9 @@ public class ServerToClientThread implements Runnable, Observer {
);
yacht.addObserver(this); // TODO: yacht can notify mark rounding message hyi25 13/8/17
player = new Player(socket, yacht);
GameState.addYacht(sourceId, yacht);
GameState.addPlayer(new Player(socket, yacht));
GameState.addPlayer(player);
}
@Override
@@ -181,8 +193,7 @@ public class ServerToClientThread implements Runnable, Observer {
int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while (socket.isConnected()) {
while (socket.isConnected() && !socket.isClosed()) {
try {
crcBuffer = new ByteArrayOutputStream();
sync1 = readByte();
@@ -200,7 +211,6 @@ public class ServerToClientThread implements Runnable, Observer {
long computedCrc = checksum.getValue();
long packetCrc = Message.bytesToLong(getBytes(4));
if (computedCrc == packetCrc) {
//System.out.println("RECEIVED A PACKET");
switch (PacketType.assignPacketType(type, payload)) {
case BOAT_ACTION:
BoatAction actionType = ServerPacketParser
@@ -237,6 +247,7 @@ public class ServerToClientThread implements Runnable, Observer {
return;
}
}
logger.warn("Closed serverToClientThread" + thread, 1);
}
public void sendSetupMessages() {
@@ -248,7 +259,11 @@ public class ServerToClientThread implements Runnable, Observer {
}
//@TODO calculate lat/lng values
xml.setRegatta(new Regatta("Party Parrot Test Server", "Bermuda Test Course", 57.6679590, 11.8503233));
xml.setRegatta(
new Regatta(
"Party Parrot Test Server", "Bermuda Test Course",
57.6679590, 11.8503233)
);
xml.setRace(race);
XMLMessage xmlMessage;
@@ -276,10 +291,12 @@ public class ServerToClientThread implements Runnable, Observer {
private int readByte() throws Exception {
int currentByte = -1;
try {
// @TODO @FIX ConnectionReset Exception when a client disconnects before it is garbage collected
currentByte = is.read();
crcBuffer.write(currentByte);
} catch (SocketException se) {
disconnectListener.notifyDisconnect(this.player);
} catch (IOException e) {
disconnectListener.notifyDisconnect(this.player);
logger.warn("Socket read failed", 1);
}
if (currentByte == -1) {
@@ -306,8 +323,7 @@ public class ServerToClientThread implements Runnable, Observer {
try {
os.write(message.getBuffer());
} catch (SocketException e) {
//serverLog("Player " + sourceId + " side socket disconnected", 1);
return;
logger.warn("Player " + sourceId + " side socket disconnected", 1);
} catch (IOException e) {
logger.warn("Message send failed", 1);
}
@@ -358,4 +374,16 @@ public class ServerToClientThread implements Runnable, Observer {
public void removeConnectionListener(ConnectionListener listener) {
connectionListeners.remove(listener);
}
public void terminate () {
try {
socket.close();
} catch (IOException ioe) {
logger.warn("IOException attempting to terminate serverToClientThread " + this.thread);
}
}
public void addDisconnectListener(DisconnectListener disconnectListener) {
this.disconnectListener = disconnectListener;
}
}