diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index ce2c3b5fddf..bd26c7edb66 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -22,11 +22,8 @@ import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage import net.mamoe.mirai.internal.network.component.withFallback import net.mamoe.mirai.internal.network.components.* -import net.mamoe.mirai.internal.network.handler.NetworkHandler +import net.mamoe.mirai.internal.network.handler.* import net.mamoe.mirai.internal.network.handler.NetworkHandler.State -import net.mamoe.mirai.internal.network.handler.NetworkHandlerContextImpl -import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory -import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport.BaseStateImpl import net.mamoe.mirai.internal.network.handler.selector.KeepAliveNetworkHandlerSelector import net.mamoe.mirai.internal.network.handler.selector.NetworkException @@ -123,11 +120,6 @@ 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 diff --git a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt index 3ac61a74f59..f71a12c747f 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt @@ -64,12 +64,12 @@ internal interface ServerList { /** * Last disconnected ip */ - var lastDisconnectedIP: String + var lastDisconnectedIP: Long /** * Last connected ip */ - var lastConnectedIP: String + var lastConnectedIP: Long /** * Get last poll ip @@ -139,8 +139,8 @@ internal class ServerListImpl( } } - override var lastDisconnectedIP: String = "" - override var lastConnectedIP: String = "" + override var lastDisconnectedIP: Long = 0L + override var lastConnectedIP: Long = 0L override fun getLastPolledIP(): String = lastPolledAddress?.host ?: "" diff --git a/mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt index 4d5dfbb8800..7a71104e285 100644 --- a/mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt @@ -94,6 +94,11 @@ internal abstract class CommonNetworkHandler( @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "KotlinRedundantDiagnosticSuppress") // can happen on some platforms protected abstract fun Conn.close() + /** + * Get the connected ip in network order + */ + protected abstract fun Conn.getConnectedIP(): Long + /** * *Single-thread* event-loop packet decoder. * @@ -244,6 +249,7 @@ internal abstract class CommonNetworkHandler( connection.join() try { context[SsoProcessor].login(this@CommonNetworkHandler) + context[ServerList].lastConnectedIP = connection.await().getConnectedIP() } catch (e: LoginFailedException) { throw LoginFailedExceptionAsNetworkException(e) } 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 4ce1364ed8c..831f4c506d6 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 @@ -169,8 +169,16 @@ internal class StatSvc { if (client.bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE) { client.bot.components[ServerList].run { kotlin.runCatching { - uOldSSOIp = lastDisconnectedIP.toIpV4Long() - uNewSSOIp = lastConnectedIP.toIpV4Long() + uOldSSOIp = if (lastDisconnectedIP in 1..2) { + -lastDisconnectedIP + } else { + lastDisconnectedIP + } + uNewSSOIp = if (lastConnectedIP in 1..2) { + -lastDisconnectedIP + } else { + lastConnectedIP + } }.onFailure { err -> client.bot.network.logger.warning({ "Exception when converting ipaddress to long: ld=${lastDisconnectedIP}, lc=${lastConnectedIP}" @@ -194,7 +202,7 @@ internal class StatSvc { fun offline( client: QQAndroidClient, regPushReason: RegPushReason = RegPushReason.appRegister - ) = impl("offline", client, 1L or 2 or 4, OnlineStatus.OFFLINE, regPushReason) + ) = impl("offline", client, 0, OnlineStatus.OFFLINE, regPushReason) private fun impl( name: String, @@ -425,9 +433,3 @@ internal class StatSvc { } } -internal fun String.toIpV4Long(): Long { - if (isEmpty()) return 0 - val split = split('.') - if (split.size != 4) return 0 - return split.mapToByteArray { it.toUByte().toByte() }.toInt().toLongUnsigned() -} diff --git a/mirai-core/src/commonMain/kotlin/utils/PlatformSocket.kt b/mirai-core/src/commonMain/kotlin/utils/PlatformSocket.kt index 985b47d57ad..80cec778202 100644 --- a/mirai-core/src/commonMain/kotlin/utils/PlatformSocket.kt +++ b/mirai-core/src/commonMain/kotlin/utils/PlatformSocket.kt @@ -24,6 +24,7 @@ import kotlin.jvm.JvmName */ internal expect class PlatformSocket : Closeable, HighwayProtocolChannel { val isOpen: Boolean + val connectedIp: Long override fun close() diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTest.kt index 3ff229f6df7..e150929efaa 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTest.kt @@ -25,7 +25,11 @@ internal abstract class TestCommonNetworkHandler( address: SocketAddress, ) : CommonNetworkHandler(context, address), ITestNetworkHandler { override suspend fun createConnection(): PlatformConn { - return PlatformConn() + return PlatformConn(address) + } + + override fun PlatformConn.getConnectedIP(): Long { + return getConnectedIPPlatform() } override fun PlatformConn.writeAndFlushOrCloseAsync(packet: OutgoingPacket) { @@ -104,4 +108,8 @@ internal expect abstract class AbstractCommonNHTest() : protected fun removeOutgoingPacketEncoder() } -internal expect class PlatformConn() \ No newline at end of file +internal expect class PlatformConn(address: SocketAddress) { + val address: SocketAddress + internal fun getConnectedIPPlatform(): Long + +} \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTestWithSelector.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTestWithSelector.kt index 6955af4c73b..fc6d30fe98c 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTestWithSelector.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractCommonNHTestWithSelector.kt @@ -30,7 +30,7 @@ internal abstract class AbstractCommonNHTestWithSelector : overrideComponents[BotOfflineEventMonitor] = BotOfflineEventMonitorImpl() } - val conn = PlatformConn() + val conn get() = PlatformConn(createAddress()) val selector = TestSelector { object : TestCommonNetworkHandler(bot, createContext(), createAddress()) { @@ -38,6 +38,7 @@ internal abstract class AbstractCommonNHTestWithSelector : override suspend fun createConnection(): PlatformConn { return conn } + } } diff --git a/mirai-core/src/commonTest/kotlin/network/framework/test/PlatformSocketIpTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/test/PlatformSocketIpTest.kt new file mode 100644 index 00000000000..88f899e2d48 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/network/framework/test/PlatformSocketIpTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.internal.network.framework.test + +import net.mamoe.mirai.internal.network.framework.PlatformConn +import net.mamoe.mirai.internal.network.handler.createSocketAddress +import net.mamoe.mirai.internal.test.runBlockingUnit +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class IpConversionTest { + private fun String.toIpV4Long(): Long { + PlatformConn(address = createSocketAddress(host = this, port = 80)).getConnectedIPPlatform().run { + return if (this in 1..2) { + -this + } else { + this + } + } + } + + @Test + fun `test bad ipAddress`() = runBlockingUnit { + assertEquals(-2, "some^ting%bad".toIpV4Long()) + assertEquals(-2, "another_bad".toIpV4Long()) + assertEquals(-2, " ".toIpV4Long()) + assertEquals(-2, "w.a.c.d".toIpV4Long()) + assertEquals(-2, "the..anotherbad......".toIpV4Long()) + assertEquals(-2, "错误的IP地址".toIpV4Long()) + } + + @Test + fun `test good ipAddress`() = runBlockingUnit { + assertTrue("www.baidu.com".toIpV4Long() > 0) + assertTrue("www.qq.com".toIpV4Long() > 0) + assertTrue("www.sohu.com".toIpV4Long() > 0) + assertTrue("www.weibo.com".toIpV4Long() > 0) + } + + @Test + fun `test plain ipAddress`() = runBlockingUnit { + assertEquals(16885952L, "192.168.1.1".toIpV4Long()) + assertEquals(4294967295L, "255.255.255.255".toIpV4Long()) + assertEquals(0L, "0.0.0.0".toIpV4Long()) + assertEquals(1869573999L, "111.111.111.111".toIpV4Long()) + } +} \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt b/mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt index c1bfcb97432..045ab1536da 100644 --- a/mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt +++ b/mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt @@ -9,7 +9,6 @@ package net.mamoe.mirai.internal.network.handler -import kotlinx.atomicfu.atomic import net.mamoe.mirai.internal.network.components.FirstLoginResult import net.mamoe.mirai.internal.network.components.SsoProcessor import net.mamoe.mirai.internal.network.framework.AbstractCommonNHTest @@ -41,7 +40,7 @@ internal class StandaloneSelectorTests : AbstractCommonNHTest() { NetworkHandlerFactory { context, address -> object : TestCommonNetworkHandler(bot, context, address) { override suspend fun createConnection(): PlatformConn { - return throwExceptionOnConnecting?.invoke() ?: PlatformConn() + return throwExceptionOnConnecting?.invoke() ?: PlatformConn(address) } } } diff --git a/mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHAddressChangedTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHAddressChangedTest.kt index 34967e99ae0..bf47772c577 100644 --- a/mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHAddressChangedTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHAddressChangedTest.kt @@ -25,8 +25,8 @@ internal class CommonNHAddressChangedTest : AbstractCommonNHTest() { networkLogger.debug("before login, Assuming both ip is empty") val lastConnectedIpOld = bot.components[ServerList].lastConnectedIP val lastDisconnectedIpOld = bot.components[ServerList].lastDisconnectedIP - assertTrue(lastConnectedIpOld.isEmpty(), "Assuming lastConnectedIp is empty") - assertTrue(lastDisconnectedIpOld.isEmpty(), "Assuming lastDisconnectedIp is empty") + assertTrue(lastConnectedIpOld == 0L, "Assuming lastConnectedIp is empty") + assertTrue(lastDisconnectedIpOld == 0L, "Assuming lastDisconnectedIp is empty") networkLogger.debug("Do login, Assuming lastConnectedIp is NOT empty") bot.login() diff --git a/mirai-core/src/jvmBaseMain/kotlin/network/impl/netty/NettyNetworkHandler.kt b/mirai-core/src/jvmBaseMain/kotlin/network/impl/netty/NettyNetworkHandler.kt index 04909eb0f43..7fccc6c78c0 100644 --- a/mirai-core/src/jvmBaseMain/kotlin/network/impl/netty/NettyNetworkHandler.kt +++ b/mirai-core/src/jvmBaseMain/kotlin/network/impl/netty/NettyNetworkHandler.kt @@ -24,8 +24,8 @@ import net.mamoe.mirai.internal.network.handler.CommonNetworkHandler import net.mamoe.mirai.internal.network.handler.NetworkHandler.State import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.utils.cast -import net.mamoe.mirai.utils.debug +import net.mamoe.mirai.utils.* +import java.net.InetSocketAddress import java.net.SocketAddress import io.netty.channel.Channel as NettyChannel @@ -131,6 +131,16 @@ internal open class NettyNetworkHandler( return contextResult.await() } + override fun io.netty.channel.Channel.getConnectedIP(): Long = this.remoteAddress().let { address -> + { + if (this.isActive && address is InetSocketAddress) { + address.address?.address?.copyOf()?.also { it.reverse() }?.toInt()?.toLongUnsigned() ?: 2L + } else { + 0L + } + } + }.invoke() + @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun io.netty.channel.Channel.close() { this.close() diff --git a/mirai-core/src/jvmBaseMain/kotlin/utils/PlatformSocket.kt b/mirai-core/src/jvmBaseMain/kotlin/utils/PlatformSocket.kt index d484f97daaf..96ab9baaa04 100644 --- a/mirai-core/src/jvmBaseMain/kotlin/utils/PlatformSocket.kt +++ b/mirai-core/src/jvmBaseMain/kotlin/utils/PlatformSocket.kt @@ -15,6 +15,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.suspendCancellableCoroutine import net.mamoe.mirai.internal.network.highway.HighwayProtocolChannel +import net.mamoe.mirai.utils.toInt +import net.mamoe.mirai.utils.toLongUnsigned import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.io.IOException @@ -31,6 +33,12 @@ internal actual class PlatformSocket : Closeable, HighwayProtocolChannel { if (::socket.isInitialized) socket.isConnected else false + actual val connectedIp: Long + get() = if (isOpen) { + socket.inetAddress.address?.copyOf()?.also { it.reverse() }?.toInt()?.toLongUnsigned() ?: 2L + } else { + 0L + } actual override fun close() { if (::socket.isInitialized) { diff --git a/mirai-core/src/jvmBaseTest/kotlin/network/framework/AbstractCommonNHTest.kt b/mirai-core/src/jvmBaseTest/kotlin/network/framework/AbstractCommonNHTest.kt index cb30348bfc1..8e19a82c7be 100644 --- a/mirai-core/src/jvmBaseTest/kotlin/network/framework/AbstractCommonNHTest.kt +++ b/mirai-core/src/jvmBaseTest/kotlin/network/framework/AbstractCommonNHTest.kt @@ -11,6 +11,12 @@ package net.mamoe.mirai.internal.network.framework import kotlinx.coroutines.ExecutorCoroutineDispatcher import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory +import net.mamoe.mirai.internal.network.handler.SocketAddress +import net.mamoe.mirai.internal.network.handler.getHost +import net.mamoe.mirai.utils.toInt +import net.mamoe.mirai.utils.toLongUnsigned +import java.net.InetAddress +import java.net.UnknownHostException import kotlin.test.AfterTest /** @@ -51,7 +57,16 @@ internal actual abstract class AbstractCommonNHTest actual constructor() : } } - actual val conn: PlatformConn = NettyNHTestChannel() + actual val conn: PlatformConn get() = PlatformConn(address = createAddress()) +} + +internal actual class PlatformConn actual constructor(actual val address: SocketAddress) : NettyNHTestChannel() { + actual fun getConnectedIPPlatform(): Long { + return (address.address ?: try { + InetAddress.getByName(address.getHost()) + } catch (e: UnknownHostException) { + null + })?.address?.copyOf()?.also { it.reverse() }?.toInt()?.toLongUnsigned() ?: 2L + } } -internal actual typealias PlatformConn = NettyNHTestChannel diff --git a/mirai-core/src/jvmBaseTest/kotlin/network/framework/NettyNHTestChannel.kt b/mirai-core/src/jvmBaseTest/kotlin/network/framework/NettyNHTestChannel.kt index 6636c936f67..c2c9117fc77 100644 --- a/mirai-core/src/jvmBaseTest/kotlin/network/framework/NettyNHTestChannel.kt +++ b/mirai-core/src/jvmBaseTest/kotlin/network/framework/NettyNHTestChannel.kt @@ -23,7 +23,7 @@ import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.error -internal class NettyNHTestChannel( +internal sealed class NettyNHTestChannel( var fakeServer: (NettyNHTestChannel.(msg: Any?) -> Unit)?, ) : EmbeddedChannel() { constructor() : this(null) diff --git a/mirai-core/src/mingwX64Main/cinterop/Socket.def b/mirai-core/src/mingwX64Main/cinterop/Socket.def index debd8e44cff..75767016333 100644 --- a/mirai-core/src/mingwX64Main/cinterop/Socket.def +++ b/mirai-core/src/mingwX64Main/cinterop/Socket.def @@ -1,5 +1,8 @@ headers = winsock.h +linkerOpts = -lWS2_32 \ + -lDnsapi + --- #define WIN32_LEAN_AND_MEAN #include @@ -7,32 +10,54 @@ headers = winsock.h #include #include #include +#include + +static unsigned long get_ulong_ip_by_name(char* host) { + DNS_RECORDA* dns_record; + if (strlen(host) == 0) { + return 0; + } + int dns_result = DnsQuery_A(host, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &dns_record, NULL); + if (dns_result == DNS_RCODE_NOERROR && dns_record != NULL) { + unsigned long result = dns_record->Data.A.IpAddress; + DnsRecordListFree(dns_record, DnsFreeRecordList); + return result; + } + else { + return 2; + } +} + +static unsigned long socket_get_connected_ip(SOCKET sockfd) { + struct sockaddr_in peer_addr; + int peer_addr_size = sizeof(peer_addr); + if (!(sockfd > 0)) { + return 1; + } + if (getpeername(sockfd, (SOCKADDR*)&peer_addr, &peer_addr_size) == 0) { + return peer_addr.sin_addr.s_addr; + } + return 2; +} -static SOCKET socket_create_connect(char *host, unsigned short port) { - SOCKADDR_STORAGE local_addr = {0}; - SOCKADDR_STORAGE remote_addr = {0}; - DWORD local_addr_size = sizeof(local_addr); - DWORD remote_addr_size = sizeof(remote_addr); - char port_name[6]; - int sockfd; +static SOCKET socket_create_connect(char* host, char* port_name) { + SOCKADDR_STORAGE local_addr = { 0 }; + SOCKADDR_STORAGE remote_addr = { 0 }; + DWORD local_addr_size = sizeof(local_addr); + DWORD remote_addr_size = sizeof(remote_addr); + int sockfd; - sprintf(port_name, "%d", (int)port); + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + return INVALID_SOCKET; + } + if (!WSAConnectByNameA(sockfd, host, port_name, &local_addr_size, (SOCKADDR*)&local_addr, &remote_addr_size, (SOCKADDR*)&remote_addr, NULL, NULL)) { + closesocket(sockfd); + return INVALID_SOCKET; + } - if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET) { - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - return INVALID_SOCKET; - } - } else { - int ipv6only = 0; - setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only)); - } - if (!WSAConnectByNameA(sockfd, host, port_name, &local_addr_size, (SOCKADDR*)&local_addr, &remote_addr_size, (SOCKADDR*)&remote_addr, NULL, NULL)) { - closesocket(sockfd); - return INVALID_SOCKET; - } - if (setsockopt(sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR) { - closesocket(sockfd); - return INVALID_SOCKET; - } - return sockfd; + if (setsockopt(sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR) { + closesocket(sockfd); + return INVALID_SOCKET; + } + return sockfd; } \ No newline at end of file diff --git a/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt b/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt index c5842029772..04fb647aaf4 100644 --- a/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt +++ b/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt @@ -21,6 +21,7 @@ import net.mamoe.mirai.utils.ByteArrayPool import net.mamoe.mirai.utils.DEFAULT_BUFFER_SIZE import net.mamoe.mirai.utils.toReadPacket import platform.posix.* +import sockets.socket_get_connected_ip import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -43,6 +44,12 @@ internal actual class PlatformSocket( actual val isOpen: Boolean get() = send(socket, null, 0, 0).convert() != 0L + actual val connectedIp: Long + get() = if (isOpen) { + sockets.socket_get_connected_ip(socket).toLong() + } else { + 0L + } actual override fun close() { closesocket(socket) @@ -104,7 +111,7 @@ internal actual class PlatformSocket( serverIp: String, serverPort: Int ): PlatformSocket { - val r = sockets.socket_create_connect(serverIp.cstr, serverPort.toUShort()) + val r = sockets.socket_create_connect(serverIp.cstr, serverPort.toString().cstr) if (r == INVALID_SOCKET) error("Failed socket_create_connect: $r") return PlatformSocket(r) } diff --git a/mirai-core/src/nativeMain/kotlin/network/handler/NativeNetworkHandler.kt b/mirai-core/src/nativeMain/kotlin/network/handler/NativeNetworkHandler.kt index 599d40711c3..d9586bb9f6a 100644 --- a/mirai-core/src/nativeMain/kotlin/network/handler/NativeNetworkHandler.kt +++ b/mirai-core/src/nativeMain/kotlin/network/handler/NativeNetworkHandler.kt @@ -36,7 +36,7 @@ internal class NativeNetworkHandler( } internal inner class NativeConn( - private val socket: PlatformSocket, + internal val socket: PlatformSocket, ) : Closeable, CoroutineScope by coroutineContext.childScope("NativeConn") { private val decodePipeline: PacketDecodePipeline = PacketDecodePipeline(this.coroutineContext) @@ -102,6 +102,10 @@ internal class NativeNetworkHandler( } } + override fun NativeConn.getConnectedIP(): Long { + return this.socket.connectedIp + } + @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun NativeConn.close() { this.close() diff --git a/mirai-core/src/nativeTest/kotlin/network/framework/AbstractCommonNHTest.kt b/mirai-core/src/nativeTest/kotlin/network/framework/AbstractCommonNHTest.kt index fa0e6fc9f9f..ab1a1fd16ea 100644 --- a/mirai-core/src/nativeTest/kotlin/network/framework/AbstractCommonNHTest.kt +++ b/mirai-core/src/nativeTest/kotlin/network/framework/AbstractCommonNHTest.kt @@ -9,7 +9,12 @@ package net.mamoe.mirai.internal.network.framework +import kotlinx.cinterop.cstr import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory +import net.mamoe.mirai.internal.network.handler.SocketAddress +import net.mamoe.mirai.utils.mapToByteArray +import net.mamoe.mirai.utils.toInt +import net.mamoe.mirai.utils.toLongUnsigned /** * Without selector. When network is closed, it will not reconnect, so that you can check for its states. @@ -32,8 +37,22 @@ internal actual abstract class AbstractCommonNHTest actual constructor() : protected actual fun removeOutgoingPacketEncoder() { } - actual val conn: PlatformConn = PlatformConn() + actual val conn: PlatformConn get() = PlatformConn(createAddress()) } -internal actual class PlatformConn \ No newline at end of file +internal actual class PlatformConn actual constructor(actual val address: SocketAddress) { + internal actual fun getConnectedIPPlatform(): Long { + address.host.run { + if (isEmpty()) return 0 + val split = split('.') + return if (split.size == 4 && split.all { it.toUByteOrNull() != null }) { + split.reversed().mapToByteArray { + it.toUByte().toByte() + }.toInt().toLongUnsigned() + } else sockets.get_ulong_ip_by_name(this.cstr).toLong(); + } + } + + +} \ No newline at end of file diff --git a/mirai-core/src/unixMain/cinterop/Socket.def b/mirai-core/src/unixMain/cinterop/Socket.def index 777694743aa..09c8d541278 100644 --- a/mirai-core/src/unixMain/cinterop/Socket.def +++ b/mirai-core/src/unixMain/cinterop/Socket.def @@ -5,6 +5,39 @@ headers = netdb.h #include #include #include +#include +#include +#include + +static unsigned long get_ulong_ip_by_name(char* host) { + unsigned long result; + if (strlen(host) == 0) { + return 0; + } + struct hostent* dns_result = gethostbyname(host); + if (dns_result != NULL) { + char** list_ptr = dns_result->h_addr_list; + char ip_str[16]; + if (inet_ntop(dns_result->h_addrtype, *list_ptr, ip_str, sizeof(ip_str)) != NULL) { + result = inet_addr(ip_str); + if (result > 0) { + return result; + } + } + } + return 2; +} + +static unsigned long socket_get_connected_ip(int sockfd) { + struct sockaddr_in peer_addr; + if (!(sockfd > 0)) { + return 1; + } + if (!getpeername(sockfd, (struct sockaddr*)&peer_addr, sizeof(peer_addr))) { + return peer_addr.sin_addr.s_addr; + } + return 2; +} static int socket_create_connect(char *host, ushort port) { struct hostent *he; diff --git a/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt b/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt index f0d317923eb..e453280c3c4 100644 --- a/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt +++ b/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt @@ -23,6 +23,7 @@ import platform.posix.close import platform.posix.errno import platform.posix.recv import platform.posix.write +import sockets.socket_get_connected_ip import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -48,6 +49,12 @@ internal actual class PlatformSocket( actual val isOpen: Boolean get() = write(socket, null, 0).convert() != 0L + actual val connectedIp: Long + get() = if (isOpen) { + socket_get_connected_ip(socket).toLong() + } else { + 0L + } actual override fun close() { close(socket)