From 5f10f1d55f928ecb27631cde0152576e69ec3e72 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Tue, 26 Jul 2016 02:16:10 +0200 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lioration=20librairie=20r=C3=A9seau=20e?= =?UTF-8?q?t=20ajout=20de=20packet=20pour=20PandacubeWeb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/util/network/client/TCPClient.java | 64 +++++++++------ .../network/client/TCPClientListener.java | 29 +++++++ .../java/util/network/packet/Packet.java | 36 +++++++-- .../util/network/packet/PacketException.java | 7 ++ .../packets/global/PacketServerException.java | 39 ++++++++++ .../packets/web/PacketClientWebRequest.java | 43 +++++++++++ .../packets/web/PacketServerWebResponse.java | 32 ++++++++ .../java/util/network/server/TCPServer.java | 77 +++++++++++++------ 8 files changed, 273 insertions(+), 54 deletions(-) create mode 100644 src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java create mode 100644 src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java create mode 100644 src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java diff --git a/src/fr/pandacube/java/util/network/client/TCPClient.java b/src/fr/pandacube/java/util/network/client/TCPClient.java index 4f82ef1..544ad21 100644 --- a/src/fr/pandacube/java/util/network/client/TCPClient.java +++ b/src/fr/pandacube/java/util/network/client/TCPClient.java @@ -7,10 +7,10 @@ import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; -import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; + +import org.apache.commons.lang.builder.ToStringBuilder; import fr.pandacube.java.Pandacube; import fr.pandacube.java.util.Log; @@ -18,6 +18,7 @@ import fr.pandacube.java.util.network.packet.Packet; import fr.pandacube.java.util.network.packet.PacketClient; import fr.pandacube.java.util.network.packet.PacketException; import fr.pandacube.java.util.network.packet.PacketServer; +import fr.pandacube.java.util.network.packet.packets.global.PacketServerException; public class TCPClient extends Thread implements Closeable { @@ -40,7 +41,11 @@ public class TCPClient extends Thread implements Closeable { socket.connect(a); addr = a; listener = l; - listener.onConnect(this); + try { + listener.onConnect(this); + } catch (Exception e) { + Log.severe("Exception while calling TCPClientListener.onConnect()", e); + } } @Override @@ -61,28 +66,35 @@ public class TCPClient extends Thread implements Closeable { byte[] packetData = ByteBuffer.allocate(1 + 4 + size).put(code).put(sizeB).put(content).array(); try { - if (listener == null) throw new InvalidServerMessage( - "Le serveur ne peut actuellement pas prendre en charge de nouvelles requêtes. Les listeners n'ont pas encore été définis"); - + Packet p = Packet.constructPacket(packetData); - if (!(p instanceof PacketServer)) throw new InvalidServerMessage( - "Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName()); + if (!(p instanceof PacketServer)) + throw new PacketException(p.getClass().getCanonicalName() + " is not a subclass of PacketServer"); + + if (p instanceof PacketServerException) { + try { + listener.onServerException(this, ((PacketServerException)p).getExceptionString()); + } catch (Exception e) { + Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e); + } + } + PacketServer ps = (PacketServer) p; - listener.onPacketReceive(this, ps); - } catch (PacketException | InvalidServerMessage e) { - Log.getLogger().log(Level.SEVERE, "Message du serveur mal formé", e); + try { + listener.onPacketReceive(this, ps); + } catch (Exception e) { + Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e); + } } catch (Exception e) { - Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur", e); + Log.severe("Exception while handling packet from server", e); } } - } catch (SocketTimeoutException e) { - System.err.println("Le serveur a prit trop de temps à répondre"); } catch (Exception e) { - e.printStackTrace(); + Log.severe(e); } close(); } @@ -110,10 +122,15 @@ public class TCPClient extends Thread implements Closeable { if (isClosed.get()) return; socket.close(); isClosed.set(true); - listener.onDisconnect(this); + + try { + listener.onDisconnect(this); + } catch (Exception e) { + Log.severe("Exception while calling TCPClientListener.onDisconnect()", e); + } } } catch (IOException e) { - e.printStackTrace(); + Log.warning(e); } } @@ -130,13 +147,12 @@ public class TCPClient extends Thread implements Closeable { public boolean isClosed() { return isClosed.get() || socket.isClosed(); } - - public static class InvalidServerMessage extends RuntimeException { - private static final long serialVersionUID = 1L; - - public InvalidServerMessage(String message) { - super(message); - } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("thread", getName()) + .append("socket", socket.getRemoteSocketAddress()).toString(); } } diff --git a/src/fr/pandacube/java/util/network/client/TCPClientListener.java b/src/fr/pandacube/java/util/network/client/TCPClientListener.java index 13ef999..4b1615d 100644 --- a/src/fr/pandacube/java/util/network/client/TCPClientListener.java +++ b/src/fr/pandacube/java/util/network/client/TCPClientListener.java @@ -1,13 +1,42 @@ package fr.pandacube.java.util.network.client; +import fr.pandacube.java.util.Log; import fr.pandacube.java.util.network.packet.PacketServer; public interface TCPClientListener { + /** + * Called when a connection is opened + * @param connection the connection which is opening + */ public void onConnect(TCPClient connection); + + /** + * Called when the server send us a PacketServerException when an exception is thrown + * server side when handling our packets or eventually when the client is concerned + * with this error.
+ * The default implementation of this method just call the internal Logger of PandacubeUtil + * to print the stacktrace of the Exception. + * @param connection the connection which just received the error + * @param exceptionString a string representation of the exception. If the server + * use this Java library, it may be a full representation of + * {@link Throwable#printStackTrace()}. + */ + public default void onServerException(TCPClient connection, String exceptionString) { + Log.severe("Exception thrown by server through " + connection + " : \n"+exceptionString); + } + /** + * Called when the server send us a packet + * @param connection the connection where the packet come from + * @param packet the packet + */ public void onPacketReceive(TCPClient connection, PacketServer packet); + /** + * Called before the connection closed + * @param connection the connection which is closing + */ public void onDisconnect(TCPClient connection); } diff --git a/src/fr/pandacube/java/util/network/packet/Packet.java b/src/fr/pandacube/java/util/network/packet/Packet.java index fda089e..c125c71 100644 --- a/src/fr/pandacube/java/util/network/packet/Packet.java +++ b/src/fr/pandacube/java/util/network/packet/Packet.java @@ -6,9 +6,31 @@ import java.util.HashMap; import java.util.Map; import fr.pandacube.java.Pandacube; +import fr.pandacube.java.util.Log; import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer; import fr.pandacube.java.util.network.packet.bytebuffer.ByteSerializable; +import fr.pandacube.java.util.network.packet.packets.global.PacketServerException; +import fr.pandacube.java.util.network.packet.packets.web.PacketClientWebRequest; +import fr.pandacube.java.util.network.packet.packets.web.PacketServerWebResponse; +/**
+ * Identification des packets réseaux
+ * byte      (xxxxxxxx)
+ *                      client :       server :
+ * clt / sv  (x-------) (0-------)     (1-------)
+ *                      0x00 - 0x7F    0x80 - 0xFF
+ * use case  (-xxx----)
+ * - web     (-000----) 0x00 - 0x0F    0x80 - 0x8F (client is Apache, server is PandacubeCore master (PandacubeWeb))
+ * - spigot  (-001----) 0x10 - 0x1F    0x90 - 0x9F (client is PandacubeSpigot, server is PandacubeCore master)
+ * - bungee  (-010----) 0x20 - 0x2F    0xA0 - 0xAF (client is PandacubeBungee, server is PandacubeCore master)
+ * - global  (-101----) 0x50 - 0x5F    0xD0 - 0xDF
+ * 
+ * - reserved if not enough packet id in certain use case
+ *           (-11x----) 0x60 - 0x7F    0xE0 - 0xFF
+ * 
+ * packet id (----xxxx)
+ * 
+ */ public abstract class Packet implements ByteSerializable { private final byte code; @@ -34,7 +56,8 @@ public abstract class Packet implements ByteSerializable { public static Packet constructPacket(byte[] data) { if (!packetTypes.containsKey(data[0])) - throw new PacketException("l'identifiant du packet ne correspond à aucun type de packet : " + data[0]); + throw new PacketException("Packet identifier not recognized: 0x" + String.format("%02X", data[0]) + + ". Maybe this packet is not registered with Packet.addPacket()"); try { Packet p = packetTypes.get(data[0]).newInstance(); @@ -42,27 +65,28 @@ public abstract class Packet implements ByteSerializable { p.deserializeFromByteBuffer(dataBuffer); return p; } catch (Exception e) { - e.printStackTrace(); - throw new PacketException("erreur lors de la construction du packet"); + throw new PacketException("Error while constructing packet", e); } } - @SuppressWarnings("unused") private static void addPacket(Class packetClass) { try { Packet p = packetClass.newInstance(); packetTypes.put(p.code, packetClass); } catch (Exception e) { - e.printStackTrace(); + Log.severe(e); } } + static { /* * Ajout des types de packets (client + serveur) */ - // addPacket(PacketToto.class); + addPacket(PacketClientWebRequest.class); + addPacket(PacketServerWebResponse.class); + addPacket(PacketServerException.class); } } diff --git a/src/fr/pandacube/java/util/network/packet/PacketException.java b/src/fr/pandacube/java/util/network/packet/PacketException.java index 463c0de..355cb6e 100644 --- a/src/fr/pandacube/java/util/network/packet/PacketException.java +++ b/src/fr/pandacube/java/util/network/packet/PacketException.java @@ -1,5 +1,12 @@ package fr.pandacube.java.util.network.packet; +/** + * + * Thrown when there is a problem when constructing, sending or handling a packet. + * + * Only the server may send a string representation of an exception to the client, not the reverse + * + */ public class PacketException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java b/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java new file mode 100644 index 0000000..64f4d13 --- /dev/null +++ b/src/fr/pandacube/java/util/network/packet/packets/global/PacketServerException.java @@ -0,0 +1,39 @@ +package fr.pandacube.java.util.network.packet.packets.global; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import fr.pandacube.java.util.network.packet.PacketServer; +import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer; + +public class PacketServerException extends PacketServer { + + private String exception; + + public PacketServerException() { + super((byte)0xE0); + } + + @Override + public void serializeToByteBuffer(ByteBuffer buffer) { + buffer.putString(exception); + } + + @Override + public void deserializeFromByteBuffer(ByteBuffer buffer) { + // TODO Auto-generated method stub + + } + + + public void setException(Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + exception = sw.toString(); + } + + public String getExceptionString() { + return exception; + } + +} diff --git a/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java b/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java new file mode 100644 index 0000000..5a1a174 --- /dev/null +++ b/src/fr/pandacube/java/util/network/packet/packets/web/PacketClientWebRequest.java @@ -0,0 +1,43 @@ +package fr.pandacube.java.util.network.packet.packets.web; + +import fr.pandacube.java.util.network.packet.PacketClient; +import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer; + +public class PacketClientWebRequest extends PacketClient { + + private String password; + private String jsonData; + + public PacketClientWebRequest() { + super((byte)0x00); + } + + @Override + public void serializeToByteBuffer(ByteBuffer buffer) { + buffer.putString(password); + buffer.putString(jsonData); + } + + @Override + public void deserializeFromByteBuffer(ByteBuffer buffer) { + password = buffer.getString(); + jsonData = buffer.getString(); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getJsonData() { + return jsonData; + } + + public void setJsonData(String jsonData) { + this.jsonData = jsonData; + } + +} diff --git a/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java b/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java new file mode 100644 index 0000000..b15c977 --- /dev/null +++ b/src/fr/pandacube/java/util/network/packet/packets/web/PacketServerWebResponse.java @@ -0,0 +1,32 @@ +package fr.pandacube.java.util.network.packet.packets.web; + +import fr.pandacube.java.util.network.packet.PacketServer; +import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer; + +public class PacketServerWebResponse extends PacketServer { + + private String jsonData; + + public PacketServerWebResponse() { + super((byte)0x80); + } + + @Override + public void serializeToByteBuffer(ByteBuffer buffer) { + buffer.putString(jsonData); + } + + @Override + public void deserializeFromByteBuffer(ByteBuffer buffer) { + jsonData = buffer.getString(); + } + + public String getJsonData() { + return jsonData; + } + + public void setJsonData(String jsonData) { + this.jsonData = jsonData; + } + +} diff --git a/src/fr/pandacube/java/util/network/server/TCPServer.java b/src/fr/pandacube/java/util/network/server/TCPServer.java index 2a28ab0..18a6f3a 100644 --- a/src/fr/pandacube/java/util/network/server/TCPServer.java +++ b/src/fr/pandacube/java/util/network/server/TCPServer.java @@ -17,12 +17,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; +import org.apache.commons.lang.builder.ToStringBuilder; + import fr.pandacube.java.Pandacube; import fr.pandacube.java.util.Log; import fr.pandacube.java.util.network.packet.Packet; import fr.pandacube.java.util.network.packet.PacketClient; +import fr.pandacube.java.util.network.packet.PacketException; import fr.pandacube.java.util.network.packet.PacketServer; import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer; +import fr.pandacube.java.util.network.packet.packets.global.PacketServerException; /** * @@ -50,7 +54,11 @@ public class TCPServer extends Thread implements Closeable { socket.setPerformancePreferences(0, 2, 1); socket.bind(new InetSocketAddress(port)); listener = l; - listener.onSocketOpen(this); + try { + listener.onSocketOpen(this); + } catch(Exception e) { + Log.severe("Exception while calling TCPServerListener.onSocketOpen()", e); + } socketName = sckName; } @@ -67,7 +75,6 @@ public class TCPServer extends Thread implements Closeable { TCPServerClientConnection co = new TCPServerClientConnection(socketClient, connectionCounterId.getAndIncrement()); clients.add(co); - listener.onClientConnect(this, co); co.start(); } catch (IOException e) { Log.getLogger().log(Level.SEVERE, "Connexion impossible avec " + socketClient.getInetAddress()); @@ -91,7 +98,11 @@ public class TCPServer extends Thread implements Closeable { in = socket.getInputStream(); out = socket.getOutputStream(); address = new InetSocketAddress(socket.getInetAddress(), socket.getPort()); - listener.onClientConnect(TCPServer.this, this); + try { + listener.onClientConnect(TCPServer.this, this); + } catch(Exception e) { + Log.severe("Exception while calling TCPServerListener.onClientConnect()", e); + } outThread = new TCPServerConnectionOutputThread(coId); outThread.start(); } @@ -102,7 +113,7 @@ public class TCPServer extends Thread implements Closeable { byte[] code = new byte[1]; while (!socket.isClosed() && in.read(code) != -1) { byte[] sizeB = new byte[4]; - if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " fermé"); + if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " closed"); int size = new ByteBuffer(sizeB, Packet.CHARSET).getInt(); @@ -117,17 +128,16 @@ public class TCPServer extends Thread implements Closeable { try { interpreteReceivedMessage(this, packetData); - } catch (InvalidClientMessage e) { - Log.getLogger().log(Level.SEVERE, "Erreur protocole de : ", e); } catch (Exception e) { - Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur", - e); - e.printStackTrace(); + Log.severe("Exception while handling packet. This exception will be sent to the client with PacketServerException packet.", e); + PacketServerException packet = new PacketServerException(); + packet.setException(e); + send(packet); } } } catch (Exception e) { - Log.getLogger().log(Level.SEVERE, "Fermeture de la connexion de " + address, e); + Log.severe("Closing connection " + address, e); } close(); @@ -149,7 +159,11 @@ public class TCPServer extends Thread implements Closeable { public void close() { if (socket.isClosed()) return; - listener.onClientDisconnect(TCPServer.this, this); + try { + listener.onClientDisconnect(TCPServer.this, this); + } catch(Exception e) { + Log.severe("Exception while calling TCPServerListener.onClientDisconnect()", e); + } clients.remove(this); try { @@ -163,9 +177,7 @@ public class TCPServer extends Thread implements Closeable { }); // provoque une exception dans le thread de sortie, et la // termine - } catch (IOException e) { - e.printStackTrace(); - } + } catch (IOException e) { } } private class TCPServerConnectionOutputThread extends Thread { @@ -200,18 +212,30 @@ public class TCPServer extends Thread implements Closeable { } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("thread", getName()) + .append("socket", socket).toString(); + } + } private void interpreteReceivedMessage(TCPServerClientConnection co, byte[] data) { Packet p = Packet.constructPacket(data); - if (!(p instanceof PacketClient)) throw new InvalidClientMessage( - "Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName()); + if (!(p instanceof PacketClient)) + throw new PacketException(p.getClass().getCanonicalName() + " is not an instanceof PacketClient"); PacketClient pc = (PacketClient) p; - listener.onPacketReceive(this, co, pc); + try { + listener.onPacketReceive(this, co, pc); + } catch(Exception e) { + Log.severe("Exception while calling TCPServerListener.onPacketReceive()", e); + } } @Override @@ -223,20 +247,25 @@ public class TCPServer extends Thread implements Closeable { socket.close(); isClosed.set(true); - listener.onSocketClose(this); + try { + listener.onSocketClose(this); + } catch(Exception e) { + Log.severe("Exception while calling TCPServerListener.onSocketClose()", e); + } } catch (IOException e) {} } public boolean isClosed() { return isClosed.get() || socket.isClosed(); } + - public static class InvalidClientMessage extends RuntimeException { - private static final long serialVersionUID = 1L; - - public InvalidClientMessage(String message) { - super(message); - } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("thread", getName()) + .append("socket", socket).toString(); } }