package electrosphere.net.client; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.logger.LoggerInterface; import electrosphere.main.Globals; import electrosphere.main.Main; import electrosphere.net.client.protocol.ClientProtocol; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.parser.net.message.ServerMessage; import electrosphere.net.parser.net.message.NetworkMessage.MessageType; import electrosphere.net.parser.net.message.ServerMessage.ServerMessageType; import electrosphere.net.parser.net.raw.NetworkParser; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.Socket; import java.net.SocketException; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Properties; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.spec.SecretKeySpec; /** * * @author amaterasu */ public class ClientNetworking implements Runnable{ String address; int port; public Socket socket; // CryptoInputStream inputStream; // CryptoOutputStream outputStream; InputStream inputStream; OutputStream outputStream; boolean initialized; NetworkParser parser; ClientProtocol clientProtocol = new ClientProtocol(); static final int MAX_CONNECTION_ATTEMPTS = 10; //set to true to also get ping and pong messages in debug logging boolean echoPings = false; //thresholds for when to send pings and to determine when we've disconnected static final long SEND_PING_THRESHOLD = 3000; static final long PING_DISCONNECT_THRESHOLD = 20000; //times for calculating ping-pong long lastPingTime = 0; long lastPongTime = 0; public ClientNetworking(String address, int port){ this.address = address; this.port = port; } @Override public void run(){ initialized = false; // final SecretKeySpec key = new SecretKeySpec(("1234567890123456").getBytes(),"AES"); // final Properties properties = new Properties(); // final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(4096, BigInteger.probablePrime(4000, new Random())); // try { // inputStream = new CryptoInputStream("AES/ECB/PKCS5Padding",properties,socket.getInputStream(),key,spec); // } catch (IOException ex) { // ex.printStackTrace(); // System.exit(1); // } // try { // outputStream = new CryptoOutputStream("AES/ECB/PKCS5Padding",properties,socket.getOutputStream(),key,spec); // } catch (IOException ex) { // ex.printStackTrace(); // System.exit(1); // } //attempt connection int connectionAttempts = 0; boolean connected = false; while(!connected){ try { this.socket = new Socket(address,port); connected = true; } catch (IOException ex) { LoggerInterface.loggerNetworking.WARNING("Client failed to connect!"); } if(!connected){ try { TimeUnit.MILLISECONDS.sleep(50); } catch (InterruptedException e) {} connectionAttempts++; } if(connectionAttempts > MAX_CONNECTION_ATTEMPTS){ LoggerInterface.loggerNetworking.ERROR("Max client connection attempts!", new Exception()); // System.exit(1); } } //create parser try { inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); parser = new NetworkParser(inputStream,outputStream); } catch (IOException ex) { LoggerInterface.loggerNetworking.ERROR("Error on client socket", ex); } //start parsing messages initialized = true; while(Main.isRunning()){ //attempt poll incoming messages parser.readMessagesIn(); //outgoing messages parser.pushMessagesOut(); //ping logic long currentTime = System.currentTimeMillis(); //basically if we haven't sent a ping in a while, send one if(currentTime - lastPingTime > SEND_PING_THRESHOLD){ queueOutgoingMessage(ServerMessage.constructPingMessage()); lastPingTime = currentTime; if(lastPongTime == 0){ lastPongTime = lastPingTime; } } if(lastPingTime - lastPongTime > PING_DISCONNECT_THRESHOLD){ //disconnected from the server LoggerInterface.loggerNetworking.WARNING("Disconnected from server"); //close socket if(socket.isConnected()){ try { socket.close(); } catch (IOException e) { LoggerInterface.loggerNetworking.ERROR("Error closing socket", e); } } //TODO: kick us back to the main menu break; } } } public void parseMessages(){ if(initialized){ while(parser.hasIncomingMessaage()){ NetworkMessage message = parser.popIncomingMessage(); //print network message printMessage(message); //do something clientProtocol.handleMessage(message); } } } /** * Print out the network message type, this only prints ping and pong if echoPings is true */ void printMessage(NetworkMessage message){ //only print ping and pong if echoPings is true if(message.getType() == MessageType.SERVER_MESSAGE){ if((((ServerMessage)message).getMessageSubtype()) == ServerMessageType.PING || (((ServerMessage)message).getMessageSubtype()) == ServerMessageType.PONG ){ if(this.echoPings == true){ LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType()); } } else { LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType()); } } else { LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType()); } } public void queueOutgoingMessage(NetworkMessage message){ parser.addOutgoingMessage(message); } public ClientProtocol getClientProtocol(){ return clientProtocol; } public void markReceivedPongMessage(){ lastPongTime = System.currentTimeMillis(); } }