From a474da5c680a7ad3e3a0cd19ab47e67456574092 Mon Sep 17 00:00:00 2001 From: nathan Date: Sat, 13 Jan 2018 23:59:36 +0100 Subject: [PATCH] Moved isEncrypted() check into KryoExtra, added register(Class clazz, int id); --- .../CryptoSerializationManager.java | 68 +++++++++++++------ .../network/util/RmiSerializationManager.java | 27 ++++---- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/dorkbox/network/connection/CryptoSerializationManager.java b/src/dorkbox/network/connection/CryptoSerializationManager.java index 98cbaee3..3cd1ccdf 100644 --- a/src/dorkbox/network/connection/CryptoSerializationManager.java +++ b/src/dorkbox/network/connection/CryptoSerializationManager.java @@ -66,7 +66,7 @@ import io.netty.buffer.ByteBuf; /** * Threads reading/writing, it messes up a single instance. it is possible to use a single kryo with the use of synchronize, however - that - * defeats the point of multi-threaded + * defeats the point of having multi-threaded serialization */ @SuppressWarnings({"unused", "StaticNonFinalField"}) public @@ -81,8 +81,6 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa @Property public static boolean useUnsafeMemory = false; - private static final String OBJECT_ID = "objectID"; - public static CryptoSerializationManager DEFAULT() { return DEFAULT(true, true); @@ -133,6 +131,15 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa this.serializer = serializer; } } + private static class ClassSerializer1 { + final Class clazz; + final int id; + + ClassSerializer1(final Class clazz, final int id) { + this.clazz = clazz; + this.id = id; + } + } private static class ClassSerializer2 { final Class clazz; final Serializer serializer; @@ -178,7 +185,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa // used to track which interface -> implementation, for use by RMI private final IntMap> rmiIdToImpl = new IntMap>(); private final IntMap> rmiIdToIface = new IntMap>(); - private final IdentityMap, Class> rmiIfacetoImpl = new IdentityMap, Class>(); + private final IdentityMap, Class> rmiIfaceToImpl = new IdentityMap, Class>(); private final IdentityMap, Class> rmiImplToIface = new IdentityMap, Class>(); /** @@ -230,7 +237,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa // This has to be for each kryo instance! InvocationResultSerializer resultSerializer = new InvocationResultSerializer(kryo); - resultSerializer.removeField(OBJECT_ID); + resultSerializer.removeField("objectID"); kryo.register(InvokeMethodResult.class, resultSerializer); kryo.register(InvocationHandler.class, invocationSerializer); @@ -246,6 +253,10 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa ClassSerializer classSerializer = (ClassSerializer) clazz; kryo.register(classSerializer.clazz, classSerializer.serializer); } + else if (clazz instanceof ClassSerializer1) { + ClassSerializer1 classSerializer = (ClassSerializer1) clazz; + kryo.register(classSerializer.clazz, classSerializer.id); + } else if (clazz instanceof ClassSerializer2) { ClassSerializer2 classSerializer = (ClassSerializer2) clazz; kryo.register(classSerializer.clazz, classSerializer.serializer, classSerializer.id); @@ -312,6 +323,34 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa return this; } + /** + * Registers the class using the specified ID. If the ID is + * already in use by the same type, the old entry is overwritten. If the ID + * is already in use by a different type, a {@link KryoException} is thrown. + * Registering a primitive also affects the corresponding primitive wrapper. + *

+ * IDs must be the same at deserialization as they were for serialization. + * + * @param id Must be >= 0. Smaller IDs are serialized more efficiently. IDs + * 0-8 are used by default for primitive types and String, but + * these IDs can be repurposed. + */ + @Override + public synchronized + RmiSerializationManager register(Class clazz, int id) { + if (initialized) { + logger.warn("Serialization manager already initialized. Ignoring duplicate register(Class, int) call."); + } + else if (clazz.isInterface()) { + throw new IllegalArgumentException("Cannot register an interface for serialization. It must be an implementation."); + } + else { + classesToRegister.add(new ClassSerializer1(clazz, id)); + } + + return this; + } + /** * Registers the class using the lowest, next available integer ID and the specified serializer. If the class is already registered, the * existing entry is updated with the new serializer. Registering a primitive also affects the corresponding primitive wrapper. @@ -372,7 +411,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa public synchronized RmiSerializationManager registerRmiInterface(Class ifaceClass) { if (initialized) { - logger.warn("Serialization manager already initialized. Ignoring duplicate registerRemote(Class, Class) call."); + logger.warn("Serialization manager already initialized. Ignoring duplicate registerRemote(Class) call."); return this; } @@ -404,11 +443,10 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa usesRmi = true; classesToRegister.add(new RemoteImplClass(ifaceClass, implClass)); - // this MUST BE UNIQUE otherwise unexpected things can happen. - Class a = this.rmiIfacetoImpl.put(ifaceClass, implClass); + // this MUST BE UNIQUE otherwise unexpected and BAD things can happen. + Class a = this.rmiIfaceToImpl.put(ifaceClass, implClass); Class b = this.rmiImplToIface.put(implClass, ifaceClass); - // this MUST BE UNIQUE otherwise unexpected things can happen. if (a != null || b != null) { throw new IllegalArgumentException("Unable to override interface (" + ifaceClass + ") and implementation (" + implClass + ") " + "because they have already been overridden by something else. It is critical that they are" + @@ -494,7 +532,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa @Override public Class getRmiImpl(Class iface) { - return rmiIfacetoImpl.get(iface); + return rmiIfaceToImpl.get(iface); } /** @@ -526,16 +564,6 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa kryoPool.put(kryo); } - /** - * Determines if this buffer is encrypted or not. - */ - public static - boolean isEncrypted(final ByteBuf buffer) { - // read off the magic byte - byte magicByte = buffer.getByte(buffer.readerIndex()); - return (magicByte & KryoExtra.crypto) == KryoExtra.crypto; - } - /** * Writes the class and object using an available kryo instance */ diff --git a/src/dorkbox/network/util/RmiSerializationManager.java b/src/dorkbox/network/util/RmiSerializationManager.java index 7df2760b..bd47dde6 100644 --- a/src/dorkbox/network/util/RmiSerializationManager.java +++ b/src/dorkbox/network/util/RmiSerializationManager.java @@ -39,6 +39,21 @@ interface RmiSerializationManager extends SerializationManager { @Override RmiSerializationManager register(Class clazz); + /** + * Registers the class using the specified ID. If the ID is + * already in use by the same type, the old entry is overwritten. If the ID + * is already in use by a different type, a {@link KryoException} is thrown. + * Registering a primitive also affects the corresponding primitive wrapper. + *

+ * IDs must be the same at deserialization as they were for serialization. + * + * @param id Must be >= 0. Smaller IDs are serialized more efficiently. IDs + * 0-8 are used by default for primitive types and String, but + * these IDs can be repurposed. + */ + @Override + RmiSerializationManager register(Class clazz, int id); + /** * Registers the class using the lowest, next available integer ID and the * specified serializer. If the class is already registered, the existing @@ -134,16 +149,4 @@ interface RmiSerializationManager extends SerializationManager { * @param implClass The implementation class of the interface */ RmiSerializationManager registerRmiImplementation(Class ifaceClass, Class implClass); - - /** - * This method overrides the interface -> implementation. This is so incoming proxy objects will get auto-changed into their correct - * implementation type, so this side of the connection knows what to do with the proxy object. - *

- * NOTE: You must have ALREADY registered the implementation class. This method just enables the proxy magic. - * This is for the "server" side, where "server" means the connection side where the implementation is used. - * - * @param ifaceClass The interface used to access the remote object - * @param implClass The implementation class of the interface - */ - // RmiSerializationManager rmiImplementation(); }