package com.cardshifter.server.clients; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.security.AccessController; import java.security.PrivilegedAction; import com.cardshifter.api.CardshifterSerializationException; import net.zomis.cardshifter.ecs.usage.CardshifterIO; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import com.cardshifter.api.ClientIO; import com.cardshifter.api.incoming.TransformerMessage; import com.cardshifter.api.messages.Message; import com.cardshifter.api.outgoing.ServerErrorMessage; import com.cardshifter.api.serial.CommunicationTransformer; import com.cardshifter.server.model.Server; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class ClientSocketHandler extends ClientIO implements Runnable { private static final Logger logger = LogManager.getLogger(ClientSocketHandler.class); private Socket socket; private final InputStream in; private final OutputStream out; private final ObjectMapper mapper = CardshifterIO.mapper(); private CommunicationTransformer transformer; public ClientSocketHandler(Server server, Socket socket) throws IOException { super(server); this.socket = socket; mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false); mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); transformer = new JsonSerialization(mapper); in = socket.getInputStream(); out = socket.getOutputStream(); } @Override public void onSendToClient(Message message) { AccessController.doPrivileged((PrivilegedAction<Void>)() -> this.realSend(message)); } private Void realSend(Message message) { try { transformer.send(message, out); } catch (CardshifterSerializationException e) { String error = "Error occured when sending message " + message; logger.fatal(error, e); // this.disconnected(); // Possibly mark client as disconnected here } return null; } @Override public void run() { logger.info("Listening for messages using " + transformer); while (socket != null && socket.isConnected()) { try { transformer.read(in, mess -> incomingMess(mess)); } catch (CardshifterSerializationException e) { logger.error(e.getMessage(), e); this.close(); } if (Thread.interrupted()) { logger.info(this + " interrupted"); close(); break; } if (socket.isClosed()) { logger.info(this + " socket closed"); close(); break; } } logger.info("End of run method for " + this); } private boolean incomingMess(Message mess) { logger.info("Received from " + this + ": " + mess); if (mess instanceof TransformerMessage) { TransformerMessage transformMess = (TransformerMessage) mess; logger.info("Tranform mess " + transformMess.getType()); switch (transformMess.getType()) { case TransformerMessage.TRANSFORM_JSON: this.transformer = new JsonSerialization(mapper); break; case TransformerMessage.TRANSFORM_BYTE: this.transformer = CardshifterIO.createByteTransformer(); break; default: throw new IllegalArgumentException("Not a known transformer: " + transformMess.getType()); } return false; } this.sentToServer(mess); return true; } @Override public void close() { this.disconnected(); try { logger.info(this + " Closing socket"); if (socket != null) { socket.close(); } } catch (IOException e) { logger.warn("Error closing", e); } socket = null; } @Override public String getRemoteAddress() { if (socket == null) { return "Not connected"; } return String.valueOf(socket.getRemoteSocketAddress()); } }