From b7869888f00ce43199e8f95f133486087bc611fd Mon Sep 17 00:00:00 2001 From: sandtechnology <20417547+sandtechnology@users.noreply.github.com> Date: Sat, 3 Jul 2021 22:04:49 +0800 Subject: [PATCH] StatSvc.Register: Provide SSO Ip and correct logic (#1240) * StatSvc.Register: Provide SSO Ip and correct logic * Remove unnessacy launch Co-authored-by: Him188 * Test for last polled ip * Normal login test for last ip * Fix test failed and remove debug code * Fix unit test and build * Optimize pollCurrent and pollAny method * Use uOldSSOIp and uNewSSOIp only when protocol is PHONE * Fix bug in toIpV4Long * Fix new line in NettyBotNormalLoginTest.kt * Using Inet4Address and toInt method for toIpV4Long * Return Unsigned Long for toIpV4Long * Remove unnessacy synchronized annotation Co-authored-by: Him188 * Using createAddress method instead of address * Moving lastDisconnectedIp and lastConnectedIp to Server List * Fix build * Fix build and remove empty line * Keeping naming consistent * Use bot.components instead of overrideComponents Co-authored-by: Him188 * Revert overrideComponents changes and add comment for overrideComponents Co-authored-by: Him188 --- .../src/commonMain/kotlin/QQAndroidBot.kt | 10 +++++ .../kotlin/network/components/ServerList.kt | 34 ++++++++++++++-- .../network/protocol/packet/login/StatSvc.kt | 26 +++++++++---- .../src/commonMain/kotlin/utils/type.kt | 15 +++++++ .../kotlin/network/ServerListTest.kt | 12 ++++++ .../AbstractNettyNHTestWithSelector.kt | 2 +- .../AbstractRealNetworkHandlerTest.kt | 6 ++- .../impl/netty/NettyAddressChangedTest.kt | 39 +++++++++++++++++++ .../impl/netty/NettyBotNormalLoginTest.kt | 2 +- 9 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index d23229232..5db01fea0 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -102,6 +102,16 @@ internal open class QQAndroidBot constructor( override fun toString(): String = "StateChangedObserver(BotOnlineEventBroadcaster)" }, + StateChangedObserver("LastConnectedAddressUpdater", State.OK) { + components[ServerList].run { + lastConnectedIP = getLastPolledIP() + } + }, + StateChangedObserver("LastDisconnectedAddressUpdater", State.CLOSED) { + components[ServerList].run { + lastDisconnectedIP = lastConnectedIP + } + }, StateChangedObserver("BotOfflineEventBroadcaster", State.OK, State.CLOSED) { new -> // logging performed by BotOfflineEventMonitor val cause = new.getCause() diff --git a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt index acae9edec..2f8791432 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt @@ -58,6 +58,22 @@ internal interface ServerList { */ fun refresh() + + /** + * Last disconnected ip + */ + var lastDisconnectedIP: String + + /** + * Last connected ip + */ + var lastConnectedIP: String + + /** + * Get last poll ip + */ + fun getLastPolledIP(): String + /** * [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty. */ @@ -100,6 +116,9 @@ internal class ServerListImpl( @Volatile private var current: Queue = ArrayDeque(initial) + @Volatile + private var lastPolledAddress: ServerAddress? = null + @Synchronized override fun setPreferred(list: Collection) { logger.info { "Server list: ${list.joinToString()}." } @@ -121,12 +140,19 @@ internal class ServerListImpl( } } + override var lastDisconnectedIP: String = "" + override var lastConnectedIP: String = "" + + override fun getLastPolledIP(): String = lastPolledAddress?.host ?: "" + /** * [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty. */ @Synchronized override fun pollCurrent(): ServerAddress? { - return current.poll() + return current.poll()?.also { address -> + lastPolledAddress = address + } } /** @@ -135,10 +161,12 @@ internal class ServerListImpl( @Synchronized override fun pollAny(): ServerAddress { if (current.isEmpty()) refresh() - return current.remove() + return current.remove().also { address -> + lastPolledAddress = address + } } override fun toString(): String { return "ServerListImpl(current.size=${current.size})" } -} \ No newline at end of file +} diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index 2d9a7d620..585b3dd59 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -30,6 +30,7 @@ import net.mamoe.mirai.internal.message.contextualBugReportException import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.components.ContactCacheService import net.mamoe.mirai.internal.network.components.ContactUpdater +import net.mamoe.mirai.internal.network.components.ServerList import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException import net.mamoe.mirai.internal.network.protocol.data.jce.* import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769 @@ -39,6 +40,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.utils.NetworkType import net.mamoe.mirai.internal.utils._miraiContentToString import net.mamoe.mirai.internal.utils.io.serialization.* +import net.mamoe.mirai.internal.utils.toIpV4Long +import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.currentTimeMillis import net.mamoe.mirai.utils.encodeToString import net.mamoe.mirai.utils.toReadPacket @@ -158,16 +161,27 @@ internal class StatSvc { client: QQAndroidClient, regPushReason: RegPushReason = RegPushReason.appRegister ) = impl("online", client, 1L or 2 or 4, client.onlineStatus, regPushReason) { - client.bot.components[ContactCacheService].friendListCache?.let { friendListCache: FriendListCache -> - iLargeSeq = friendListCache.friendListSeq - // timeStamp = friendListCache.timeStamp + if (client.bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE) { + client.bot.components[ServerList].run { + uOldSSOIp = lastDisconnectedIP.toIpV4Long() + uNewSSOIp = lastConnectedIP.toIpV4Long() + } + } else { + uOldSSOIp = 0 + uNewSSOIp = 0 } + client.bot.components[ContactCacheService].friendListCache?.let { friendListCache -> + iLargeSeq = friendListCache.friendListSeq + } + // timeStamp = friendListCache.timeStamp + strVendorName = "MIUI" + strVendorOSName = "?ONEPLUS A5000_23_17" } fun offline( client: QQAndroidClient, regPushReason: RegPushReason = RegPushReason.appRegister - ) = impl("offline", client, 0, OnlineStatus.OFFLINE, regPushReason) + ) = impl("offline", client, 1L or 2 or 4, OnlineStatus.OFFLINE, regPushReason) private fun impl( name: String, @@ -221,10 +235,6 @@ internal class StatSvc { strDevName = client.device.model.encodeToString(), strDevType = client.device.model.encodeToString(), strOSVer = client.device.version.release.encodeToString(), - uOldSSOIp = 0, - uNewSSOIp = 0, - strVendorName = "MIUI", - strVendorOSName = "?ONEPLUS A5000_23_17", // register 时还需要 /* var44.uNewSSOIp = field_127445; diff --git a/mirai-core/src/commonMain/kotlin/utils/type.kt b/mirai-core/src/commonMain/kotlin/utils/type.kt index 90b1a4f3f..77ccfe7eb 100644 --- a/mirai-core/src/commonMain/kotlin/utils/type.kt +++ b/mirai-core/src/commonMain/kotlin/utils/type.kt @@ -11,6 +11,9 @@ package net.mamoe.mirai.internal.utils import net.mamoe.mirai.contact.ContactOrBot import net.mamoe.mirai.message.data.* +import net.mamoe.mirai.utils.toInt +import net.mamoe.mirai.utils.toLongUnsigned +import java.net.Inet4Address internal fun Int.toIpV4AddressString(): String { @@ -27,6 +30,18 @@ internal fun Int.toIpV4AddressString(): String { } } +internal fun String.toIpV4Long(): Long { + return if (isEmpty()) { + 0 + } else { + try { + Inet4Address.getByName(this).address.toInt().toLongUnsigned() + } catch (e: UnknownHostException) { + -2 + } + } +} + internal fun String.chineseLength(upTo: Int): Int { return this.sumUpTo(upTo) { when (it) { diff --git a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt index ec73719ae..57c6b6c4e 100644 --- a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt @@ -27,6 +27,18 @@ internal class ServerListTest : AbstractTest() { assertNotNull(ServerListImpl().pollCurrent()) } + @Test + fun `last poll ip is updated when polled`() { + val instance = ServerListImpl() + val old = instance.getLastPolledIP() + assertNotNull(old) + assert(old.isEmpty()) + assertNotNull(instance.pollCurrent()) + val new = instance.getLastPolledIP() + assertNotNull(new) + assertNotEquals(old, new) + } + @Test fun `not empty for initial`() { assertNotNull(ServerListImpl().pollAny()) diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt index 2c9c0ebca..0242c7c56 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt @@ -34,7 +34,7 @@ internal abstract class AbstractNettyNHTestWithSelector : AbstractRealNetworkHan val channel = AbstractNettyNHTest.NettyNHTestChannel() val selector = TestSelector { - object : TestNettyNH(bot, createContext(), address) { + object : TestNettyNH(bot, createContext(), createAddress()) { override suspend fun createConnection(decodePipeline: PacketDecodePipeline): Channel = channel } } diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt index 417c9e1e0..65a24c005 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt @@ -132,11 +132,13 @@ internal sealed class AbstractRealNetworkHandlerTest : Abstr return instance } - open fun createHandler(): NetworkHandler = factory.create(createContext(), address) + open fun createHandler(): NetworkHandler = factory.create(createContext(), createAddress()) open fun createContext(): NetworkHandlerContextImpl = NetworkHandlerContextImpl(bot, networkLogger, bot.createNetworkLevelComponents()) - val address: InetSocketAddress = InetSocketAddress.createUnresolved("localhost", 123) + //Use overrideComponents to avoid StackOverflowError when applying components + open fun createAddress(): InetSocketAddress = + overrideComponents[ServerList].pollAny().let { InetSocketAddress.createUnresolved(it.host, it.port) } /////////////////////////////////////////////////////////////////////////// // Assertions diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt new file mode 100644 index 000000000..333830ea9 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt @@ -0,0 +1,39 @@ +package net.mamoe.mirai.internal.network.impl.netty + +import net.mamoe.mirai.internal.network.components.ServerList +import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest +import net.mamoe.mirai.internal.network.framework.TestNettyNH +import net.mamoe.mirai.internal.network.handler.NetworkHandler +import net.mamoe.mirai.internal.test.runBlockingUnit +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +internal class NettyAddressChangedTest : AbstractNettyNHTest() { + @Test + fun `test login ip changes`() = runBlockingUnit { + networkLogger.debug("before login, Assuming both ip is empty") + val lastConnectedIpOld = bot.components[ServerList].lastConnectedIP + val lastDisconnectedIpOld = bot.components[ServerList].lastDisconnectedIP + assert(lastConnectedIpOld.isEmpty()) { "Assuming lastConnectedIp is empty" } + assert(lastDisconnectedIpOld.isEmpty()) { "Assuming lastDisconnectedIp is empty" } + + networkLogger.debug("Do login, Assuming lastConnectedIp is NOT empty") + bot.login() + assertState(NetworkHandler.State.OK) + assertNotEquals( + lastConnectedIpOld, + bot.components[ServerList].lastConnectedIP, + "Assuming lastConnectedIp is NOT empty" + ) + + networkLogger.debug("Offline the bot, Assuming lastConnectedIp is equals lastDisconnectedIp") + (bot.network as TestNettyNH).setStateClosed() + assertState(NetworkHandler.State.CLOSED) + assertEquals( + bot.components[ServerList].lastConnectedIP, + bot.components[ServerList].lastDisconnectedIP, + "Assuming lastConnectedIp is equals lastDisconnectedIp" + ) + } +} diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt index 8bbf05c09..09bc2af14 100644 --- a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt @@ -26,7 +26,7 @@ import kotlin.test.assertFalse internal class NettyBotNormalLoginTest : AbstractNettyNHTest() { val selector = KeepAliveNetworkHandlerSelector(selectorLogger) { - super.factory.create(createContext(), address) + super.factory.create(createContext(), createAddress()) } override fun createHandler(): NetworkHandler {