From 6a590764ff4f6b3895f7897e533187f6d8dc7202 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 3 Sep 2020 02:40:32 +0200 Subject: [PATCH] Fixed issues when registering RMI via registerRmi in different orders (rmi-client/rmi-server out-of-order in different ways). --- .../serialization/ClassRegistration.kt | 5 +- .../serialization/ClassRegistrationForRmi.kt | 106 ++++++++++++++---- .../network/serialization/Serialization.kt | 12 +- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/dorkbox/network/serialization/ClassRegistration.kt b/src/dorkbox/network/serialization/ClassRegistration.kt index d3f225d5..8e83a4a9 100644 --- a/src/dorkbox/network/serialization/ClassRegistration.kt +++ b/src/dorkbox/network/serialization/ClassRegistration.kt @@ -68,8 +68,9 @@ internal abstract class ClassRegistration(val clazz: Class<*>, val serializer: S } // now, we want to save the relationship between classes and kryoId - rmi.idToIface[id] = clazz - rmi.ifaceToId[clazz] = id + // ALL REGISTRATIONS MUST BE IMPL! (only RMI can have IFACE) + rmi.idToImpl[id] = clazz + rmi.implToId[clazz] = id } open fun register(kryo: KryoExtra) {} diff --git a/src/dorkbox/network/serialization/ClassRegistrationForRmi.kt b/src/dorkbox/network/serialization/ClassRegistrationForRmi.kt index 15261523..5233badd 100644 --- a/src/dorkbox/network/serialization/ClassRegistrationForRmi.kt +++ b/src/dorkbox/network/serialization/ClassRegistrationForRmi.kt @@ -106,16 +106,77 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>, override fun register(kryo: KryoExtra, rmi: RmiHolder) { // we override this, because we ALWAYS will call our RMI registration! - if (implClass == null) { - // this means we are the RMI-CLIENT + // EVERY time initKryo() is called, this will happen. We have to ensure that every call produces the same results - // see if we have the IMPL registered? NOT LIKELY, but possible - val existingId = rmi.ifaceToId[clazz] - if (existingId != null) { - implClass = rmi.idToImpl[existingId] + // SUPER IMPORTANT: + // if RMI-CLIENT is registered, an IFACE will be present + // if RMI-SERVER is registered, and IFACE+IMPL will be present + // Both IFACE+IMPL must be checked when deciding if something needs to be overloaded, but ONLY for registerRmi + + // check to see if we have already registered this as RMI-CLIENT + val alreadyRegistered = rmi.ifaceToId[clazz] != null + + if (alreadyRegistered) { + // if we are ALREADY registered, then we have to make sure that RMI-CLIENT doesn't override RMI-SERVER... + val previousId = rmi.ifaceToId[clazz] + if (rmi.idToImpl[previousId] != null) { + // the impl was registered, which means that ANOTHER registration registered as RMI-SERVER. + + if (implClass == null) { + // we are RMI-CLIENT. + // remove this registration, because we ALREADY have RMI-SERVER registered, and changing it to RMI-CLIENT will break rmi. + info = "CONFLICTED $previousId -> (RMI) Ignored duplicate registration for ${clazz.name}" + + // mark this for later, so we don't try to do something with it + id = IGNORE_REGISTRATION + return + } else { + // Who cares. we are RMI-SERVER, so redo the registration info. + // MAYBE there are duplicates, but we don't care because whatever is registered as RMI-SERVER is the authority + val registration = kryo.classResolver.getRegistration(clazz) + if (registration != null) { + id = registration.id + + // override that registration + kryo.register(implClass, serializer, id) + } + else { + // now register the impl class + id = kryo.register(implClass, serializer).id + } + } + } else { + // we don't have an IMPL registered (this means, only RMI-CLIENT was registered + + // if we are RMI-SERVER, then we register, if we are RMI-CLIENT, then we are a duplicate registration (and should be ignored) + if (implClass != null) { + // this means we are the RMI-SERVER + val registration = kryo.classResolver.getRegistration(clazz) + if (registration != null) { + id = registration.id + + // override that registration + kryo.register(implClass, serializer, id) + } + else { + // now register the impl class + id = kryo.register(implClass, serializer).id + } + } else { + // duplicate. ignore! + // do nothing, because this is ALREADY registered for RMI + info = "CONFLICTED $previousId -> (RMI) Ignored duplicate registration for ${clazz.name}" + + // mark this for later, so we don't try to do something with it + id = IGNORE_REGISTRATION + return + } } + } else { + // this means we were NOT already registered if (implClass == null) { + // this means we are the RMI-CLIENT // then we just register the interface class! val registration = kryo.classResolver.getRegistration(clazz) @@ -129,27 +190,24 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>, // just register the iface class id = kryo.register(clazz, serializer).id } + } else { + // RMI-SERVER + + // this means we are the RMI-SERVER + val registration = kryo.classResolver.getRegistration(clazz) + if (registration != null) { + id = registration.id + + // override that registration + kryo.register(implClass, serializer, id) + } + else { + // now register the impl class + id = kryo.register(implClass, serializer).id + } } } - - if (implClass != null) { - // this means we are the RMI-SERVER - val registration = kryo.classResolver.getRegistration(implClass) // we cannot register iface classes! - if (registration != null) { - id = registration.id - - // override that registration - kryo.register(implClass, serializer, id) - } - else { - // now register the impl class - id = kryo.register(implClass, serializer).id - } - } - - - // have to get the ID for the interface (if it exists) info = if (implClass == null) { "Registered $id -> (RMI-CLIENT) ${clazz.name}" diff --git a/src/dorkbox/network/serialization/Serialization.kt b/src/dorkbox/network/serialization/Serialization.kt index 05f8e6da..519ad7f9 100644 --- a/src/dorkbox/network/serialization/Serialization.kt +++ b/src/dorkbox/network/serialization/Serialization.kt @@ -333,7 +333,8 @@ open class Serialization(private val references: Boolean = true, private val fac classesToRegister.add(ClassRegistration3(it)) } - initializeClassRegistrations() + val kryo = initKryo() // this will initialize the class registrations + initializeClassRegistrations(kryo) } else { if (!initialized.compareAndSet(expect = false, update = true)) { // the client CAN initialize more than once, since initialization happens in the handshake now @@ -344,9 +345,7 @@ open class Serialization(private val references: Boolean = true, private val fac } } - private fun initializeClassRegistrations(): Boolean { - val kryo = initKryo() - + private fun initializeClassRegistrations(kryo: KryoExtra): Boolean { // now MERGE all of the registrations (since we can have registrations overwrite newer/specific registrations based on ID // in order to get the ID's, these have to be registered with a kryo instance! val mergedRegistrations = mutableListOf() @@ -474,6 +473,7 @@ open class Serialization(private val references: Boolean = true, private val fac val classesToRegisterForRmi = listOf(*classesToRegister.toTypedArray()) as List classesToRegister.clear() + // NOTE: to be clear, the "client" can ONLY registerRmi(IFACE, IMPL), to have extra info as the RMI-SERVER!! @@ -530,10 +530,10 @@ open class Serialization(private val references: Boolean = true, private val fac } // we have to re-init so the registrations are set! - initKryo() + kryo = initKryo() // now do a round-trip through the class registrations - return initializeClassRegistrations() + return initializeClassRegistrations(kryo) } /**