Fixes in epoll event-loop and pinger
This commit is contained in:
parent
eb19b3e36a
commit
834d12c17b
@ -17,9 +17,11 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(Dependencies.kotlin_atomicfu)
|
||||||
implementation(Dependencies.kotlin_coroutines_core)
|
implementation(Dependencies.kotlin_coroutines_core)
|
||||||
implementation(Dependencies.kotlin_datetime)
|
implementation(Dependencies.kotlin_datetime)
|
||||||
implementation(Dependencies.int_serializers)
|
implementation(Dependencies.int_serializers)
|
||||||
|
implementation(project(":modules:utilities"))
|
||||||
implementation(project(":modules:low-level:sockets"))
|
implementation(project(":modules:low-level:sockets"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package ru.landgrafhomyak.bgtu.networks0.icmp
|
||||||
|
|
||||||
|
import ru.landgrafhomyak.utility.IntSerializers
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
|
class IcmpEchoHeader(
|
||||||
|
val identifier_be: UShort,
|
||||||
|
val seqNo_be: UShort,
|
||||||
|
) : IcmpHeader {
|
||||||
|
override val type: UByte get() = 0u
|
||||||
|
override val code: UByte get() = 0u
|
||||||
|
|
||||||
|
override fun checksum(withData: UByteArray): UShort = Ipv4Checksum.calculate { c ->
|
||||||
|
c.addFirstByte(this.type)
|
||||||
|
c.addSecondByte(this.code)
|
||||||
|
c.addWord(this.identifier_be)
|
||||||
|
c.addWord(this.seqNo_be)
|
||||||
|
c.addTrailingData(withData)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(withData: UByteArray): UByteArray {
|
||||||
|
val serialized = UByteArray(withData.size + 8)
|
||||||
|
IntSerializers.encode8Bu(serialized, 0, this.type)
|
||||||
|
IntSerializers.encode8Bu(serialized, 1, this.code)
|
||||||
|
IntSerializers.encode16beHu(serialized, 2, this.checksum(withData))
|
||||||
|
IntSerializers.encode16beHu(serialized, 4, this.identifier_be)
|
||||||
|
IntSerializers.encode16beHu(serialized, 6, this.seqNo_be)
|
||||||
|
withData.copyInto(serialized, 8)
|
||||||
|
return serialized
|
||||||
|
}
|
||||||
|
}
|
@ -1,112 +0,0 @@
|
|||||||
package ru.landgrafhomyak.bgtu.networks0.icmp
|
|
||||||
|
|
||||||
import kotlin.coroutines.Continuation
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import kotlinx.coroutines.withTimeout
|
|
||||||
import kotlinx.datetime.Clock
|
|
||||||
import kotlinx.datetime.Instant
|
|
||||||
import kotlinx.coroutines.sync.Mutex as CMutex
|
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.IcmpSocket
|
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
|
||||||
import ru.landgrafhomyak.utility.IntSerializers
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
|
||||||
class PingSocket : AutoCloseable {
|
|
||||||
private val _rawSocket: IcmpSocket
|
|
||||||
private val _mapSync: CMutex
|
|
||||||
private val _resumeMap: HashMap<ShortKeyPair, Continuation<Unit>>
|
|
||||||
private val _recvCoro: Job
|
|
||||||
|
|
||||||
internal constructor(rawSocket: IcmpSocket) {
|
|
||||||
safeAutoClose2(onAbort = rawSocket::close) {
|
|
||||||
this._rawSocket = rawSocket
|
|
||||||
this._resumeMap = HashMap()
|
|
||||||
this._mapSync = CMutex()
|
|
||||||
this._recvCoro = CoroutineScope(Dispatchers.Default).launch { this@PingSocket._recvRoutine() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ShortKeyPair(val identifier: UShort, val seqNo: UShort) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (other !is ShortKeyPair) return false
|
|
||||||
return this.identifier == other.identifier && this.seqNo == other.seqNo
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return ((this.identifier.toUInt() shl 16) or (this.seqNo).toUInt()).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = "<icmp ping key pair identifier=${this.identifier} seq_no=${this.seqNo}>"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun _generateKeyPair(): ShortKeyPair {
|
|
||||||
val timestamp = Clock.System.now()
|
|
||||||
return ShortKeyPair(
|
|
||||||
identifier = (timestamp.epochSeconds ushr 13).toULong().toUShort(),
|
|
||||||
seqNo = ((timestamp.epochSeconds shl 3) or ((((timestamp.nanosecondsOfSecond ushr 27) and 7).toLong())) and 0xFFFF).toULong().toUShort(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun ping(timeoutMillis: UInt): UInt? {
|
|
||||||
var isLocked = true
|
|
||||||
val start: Instant
|
|
||||||
this._mapSync.lock()
|
|
||||||
safeAutoClose1(finally = { if (isLocked) this._mapSync.unlock() }) {
|
|
||||||
val key = this._generateKeyPair()
|
|
||||||
val header = IcmpPingHeader(identifier_be = key.identifier, seqNo_be = key.seqNo)
|
|
||||||
val serialized = header.serialize(PingSocket.randomData)
|
|
||||||
start = Clock.System.now()
|
|
||||||
this._rawSocket.sendRaw(serialized)
|
|
||||||
try {
|
|
||||||
withTimeout(timeoutMillis.toULong().toLong()) {
|
|
||||||
suspendCancellableCoroutine<Unit> { continuation ->
|
|
||||||
if (key in this@PingSocket._resumeMap)
|
|
||||||
throw RuntimeException("Key duplication (shouldn't happen)")
|
|
||||||
this@PingSocket._resumeMap[key] = continuation
|
|
||||||
this@PingSocket._mapSync.unlock()
|
|
||||||
isLocked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (_: TimeoutCancellationException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val td = Clock.System.now() - start
|
|
||||||
return td.inWholeMilliseconds.toUInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun _recvRoutine() {
|
|
||||||
try {
|
|
||||||
// todo handle errors
|
|
||||||
while (true) {
|
|
||||||
val raw = this._rawSocket.recvRaw()
|
|
||||||
if (raw.size < 8) continue
|
|
||||||
val key = ShortKeyPair(identifier = IntSerializers.decode16beHu(raw, 4), seqNo = IntSerializers.decode16beHu(raw, 6))
|
|
||||||
val continuation = this._mapSync.withLock { this._resumeMap.remove(key) }
|
|
||||||
if (continuation == null) continue
|
|
||||||
continuation.resume(Unit)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@Suppress("SpellCheckingInspection")
|
|
||||||
private val randomData = "abcdefghijklmnopqrstuvwabcdefghi".encodeToByteArray().asUByteArray()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,107 @@
|
|||||||
|
package ru.landgrafhomyak.bgtu.networks0.icmp
|
||||||
|
|
||||||
|
import kotlinx.atomicfu.AtomicRef
|
||||||
|
import kotlinx.atomicfu.atomic
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
|
import kotlinx.datetime.Clock
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.IcmpSocket
|
||||||
|
import ru.landgrafhomyak.bgtu.networks0.utilities.compareAndExchange
|
||||||
|
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||||
|
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||||
|
import ru.landgrafhomyak.utility.IntSerializers
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
|
class Pinger1 : AutoCloseable {
|
||||||
|
private enum class State {
|
||||||
|
READY, CONNECTED, CLOSED
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _rawSocket: IcmpSocket
|
||||||
|
private var _state: AtomicRef<State>
|
||||||
|
|
||||||
|
|
||||||
|
internal constructor(rawSocket: IcmpSocket) {
|
||||||
|
safeAutoClose2(onAbort = rawSocket::close) {
|
||||||
|
this._state = atomic(State.READY)
|
||||||
|
this._rawSocket = rawSocket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ShortKeyPair(val identifier: UShort, val seqNo: UShort) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is ShortKeyPair) return false
|
||||||
|
return this.identifier == other.identifier && this.seqNo == other.seqNo
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return ((this.identifier.toUInt() shl 16) or (this.seqNo).toUInt()).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = "<icmp ping key pair identifier=${this.identifier} seq_no=${this.seqNo}>"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun _generateKeyPair(): ShortKeyPair {
|
||||||
|
val timestamp = Clock.System.now()
|
||||||
|
return ShortKeyPair(
|
||||||
|
identifier = (timestamp.epochSeconds ushr 13).toULong().toUShort(),
|
||||||
|
seqNo = ((timestamp.epochSeconds shl 3) or ((((timestamp.nanosecondsOfSecond ushr 27) and 7).toLong())) and 0xFFFF).toULong().toUShort(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun ping(timeoutMillis: UInt): UInt? {
|
||||||
|
when (this._state.compareAndExchange(State.READY, State.CONNECTED)) {
|
||||||
|
State.CLOSED -> throw IllegalStateException("Pinger is closed")
|
||||||
|
State.CONNECTED -> throw IllegalStateException("Pinger is busy with another thread/coroutine")
|
||||||
|
State.READY -> {}
|
||||||
|
}
|
||||||
|
safeAutoClose1(finally = { this._state.value = State.READY }) {
|
||||||
|
val start: Instant
|
||||||
|
val key = this._generateKeyPair()
|
||||||
|
val header = IcmpPingHeader(identifier_be = key.identifier, seqNo_be = key.seqNo)
|
||||||
|
val serialized = header.serialize(Pinger1.payloadLikeInPingProgramm)
|
||||||
|
start = Clock.System.now()
|
||||||
|
this._rawSocket.sendRaw(serialized)
|
||||||
|
try {
|
||||||
|
withTimeout(timeoutMillis.toULong().toLong()) {
|
||||||
|
while (true)
|
||||||
|
if (this@Pinger1._dispatchResponse(key, this@Pinger1._rawSocket.recvRaw())) return@withTimeout
|
||||||
|
}
|
||||||
|
} catch (_: TimeoutCancellationException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val td = Clock.System.now() - start
|
||||||
|
return td.inWholeMilliseconds.toUInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun _dispatchResponse(expected: ShortKeyPair, raw: UByteArray): Boolean {
|
||||||
|
if (raw.size < 8) return false
|
||||||
|
val actualKey = ShortKeyPair(identifier = IntSerializers.decode16beHu(raw, 4), seqNo = IntSerializers.decode16beHu(raw, 6))
|
||||||
|
val echoHeader = IcmpEchoHeader(identifier_be = actualKey.identifier, seqNo_be = actualKey.seqNo)
|
||||||
|
if (actualKey != expected) return false
|
||||||
|
if (IntSerializers.decode8Bu(raw, 0) != echoHeader.type) return false
|
||||||
|
if (IntSerializers.decode8Bu(raw, 1) != echoHeader.code) return false
|
||||||
|
val data = raw.sliceArray(8..<(raw.size))
|
||||||
|
if (!data.contentEquals(Pinger1.payloadLikeInPingProgramm)) return false
|
||||||
|
if (echoHeader.checksum(data) != IntSerializers.decode16beHu(raw, 2)) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
when (this._state.compareAndExchange(State.READY, State.CLOSED)) {
|
||||||
|
State.CLOSED -> throw IllegalStateException("Pinger is closed")
|
||||||
|
State.CONNECTED -> throw IllegalStateException("Can't close pinger while it measures time")
|
||||||
|
State.READY -> {}
|
||||||
|
}
|
||||||
|
this._rawSocket.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
private val payloadLikeInPingProgramm = "abcdefghijklmnopqrstuvwabcdefghi".encodeToByteArray().asUByteArray()
|
||||||
|
}
|
||||||
|
}
|
@ -2,5 +2,5 @@ package ru.landgrafhomyak.bgtu.networks0.icmp
|
|||||||
|
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.SocketEventLoopScope
|
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.SocketEventLoopScope
|
||||||
|
|
||||||
fun SocketEventLoopScope.pingSocket_IPv4(addr: String): PingSocket = PingSocket(this.icmp_IPv4(addr))
|
fun SocketEventLoopScope.pinger_IPv4(addr: String): Pinger1 = Pinger1(this.icmp_IPv4(addr))
|
||||||
fun SocketEventLoopScope.pingSocket_IPv6(addr: String): PingSocket = PingSocket(this.icmp_IPv6(addr))
|
fun SocketEventLoopScope.pinger_IPv6(addr: String): Pinger1 = Pinger1(this.icmp_IPv6(addr))
|
@ -2,7 +2,6 @@ package ru.landgrafhomyak.bgtu.networks0.low_level.sockets
|
|||||||
|
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
import kotlinx.cinterop.CValue
|
import kotlinx.cinterop.CValue
|
||||||
import kotlinx.cinterop.ExperimentalForeignApi
|
import kotlinx.cinterop.ExperimentalForeignApi
|
||||||
import kotlinx.cinterop.StableRef
|
import kotlinx.cinterop.StableRef
|
||||||
@ -13,8 +12,6 @@ import kotlinx.cinterop.get
|
|||||||
import kotlinx.cinterop.memScoped
|
import kotlinx.cinterop.memScoped
|
||||||
import kotlinx.cinterop.ptr
|
import kotlinx.cinterop.ptr
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import platform.linux.EPOLLERR
|
|
||||||
import platform.linux.EPOLLHUP
|
|
||||||
import platform.linux.EPOLLIN
|
import platform.linux.EPOLLIN
|
||||||
import platform.linux.EPOLLONESHOT
|
import platform.linux.EPOLLONESHOT
|
||||||
import platform.linux.EPOLLOUT
|
import platform.linux.EPOLLOUT
|
||||||
@ -25,17 +22,17 @@ import platform.linux.epoll_create
|
|||||||
import platform.linux.epoll_ctl
|
import platform.linux.epoll_ctl
|
||||||
import platform.linux.epoll_event
|
import platform.linux.epoll_event
|
||||||
import platform.linux.epoll_wait
|
import platform.linux.epoll_wait
|
||||||
|
import platform.posix.close as close_lowlevel
|
||||||
import platform.linux.inet_pton
|
import platform.linux.inet_pton
|
||||||
import platform.posix.AF_INET
|
import platform.posix.AF_INET
|
||||||
import platform.posix.sockaddr_in
|
import platform.posix.sockaddr_in
|
||||||
import platform.posix.sockaddr_in6
|
import platform.posix.sockaddr_in6
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.Mutex as TMutex
|
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.withLock
|
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.withLock
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2e
|
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.Mutex as TMutex
|
||||||
|
|
||||||
@OptIn(ExperimentalForeignApi::class)
|
@OptIn(ExperimentalForeignApi::class)
|
||||||
@Suppress("JoinDeclarationAndAssignment", "ConvertSecondaryConstructorToPrimary", "FunctionName")
|
@Suppress("JoinDeclarationAndAssignment", "ConvertSecondaryConstructorToPrimary", "FunctionName")
|
||||||
@ -76,6 +73,7 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
|||||||
this.data.fd = metadata.fd
|
this.data.fd = metadata.fd
|
||||||
this.data.ptr = metadata.stableRef.asCPointer()
|
this.data.ptr = metadata.stableRef.asCPointer()
|
||||||
}
|
}
|
||||||
|
if (metadata.read != null || metadata.write != null) {
|
||||||
if (!metadata.isAddedToEpoll) {
|
if (!metadata.isAddedToEpoll) {
|
||||||
if (0 != epoll_ctl(this._epollDescriptor, EPOLL_CTL_ADD, metadata.fd, ee))
|
if (0 != epoll_ctl(this._epollDescriptor, EPOLL_CTL_ADD, metadata.fd, ee))
|
||||||
PosixUtilities.throwErrno { d -> RuntimeException("Failed to add fd to epoll: $d") }
|
PosixUtilities.throwErrno { d -> RuntimeException("Failed to add fd to epoll: $d") }
|
||||||
@ -84,6 +82,13 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
|||||||
if (0 != epoll_ctl(this._epollDescriptor, EPOLL_CTL_MOD, metadata.fd, ee))
|
if (0 != epoll_ctl(this._epollDescriptor, EPOLL_CTL_MOD, metadata.fd, ee))
|
||||||
PosixUtilities.throwErrno { d -> RuntimeException("Failed to modify fd in epoll: $d") }
|
PosixUtilities.throwErrno { d -> RuntimeException("Failed to modify fd in epoll: $d") }
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (metadata.isAddedToEpoll) {
|
||||||
|
if (0 != epoll_ctl(this._epollDescriptor, EPOLL_CTL_DEL, metadata.fd, null))
|
||||||
|
PosixUtilities.throwErrno { d -> RuntimeException("Failed to remove fd from epoll: $d") }
|
||||||
|
metadata.isAddedToEpoll = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun _remove(metadata: _SocketMetadata) {
|
private fun _remove(metadata: _SocketMetadata) {
|
||||||
@ -95,22 +100,38 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun _waitForRead(metadata: _SocketMetadata) = suspendCoroutine { continuation ->
|
private suspend fun _waitForRead(metadata: _SocketMetadata) {
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
metadata.sync.withLock {
|
metadata.sync.withLock {
|
||||||
if (metadata.read != null)
|
if (metadata.read != null)
|
||||||
throw IllegalStateException("Socket already waiting for read")
|
throw IllegalStateException("Socket already waiting for read")
|
||||||
metadata.read = continuation
|
metadata.read = continuation
|
||||||
this._schedule(metadata)
|
this._schedule(metadata)
|
||||||
|
continuation.invokeOnCancellation {
|
||||||
|
metadata.sync.withLock {
|
||||||
|
metadata.read = null
|
||||||
|
this._schedule(metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun _waitForWrite(metadata: _SocketMetadata) = suspendCoroutine { continuation ->
|
private suspend fun _waitForWrite(metadata: _SocketMetadata) {
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
metadata.sync.withLock {
|
metadata.sync.withLock {
|
||||||
if (metadata.write != null)
|
if (metadata.write != null)
|
||||||
throw IllegalStateException("Socket already waiting for write")
|
throw IllegalStateException("Socket already waiting for write")
|
||||||
metadata.write = continuation
|
metadata.write = continuation
|
||||||
this._schedule(metadata)
|
this._schedule(metadata)
|
||||||
|
continuation.invokeOnCancellation {
|
||||||
|
metadata.sync.withLock {
|
||||||
|
metadata.write = null
|
||||||
|
this._schedule(metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +168,9 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
|||||||
|
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
TODO("Not yet implemented")
|
this._socketsCount.close("There are still opened sockets bound to this event-loop")
|
||||||
|
if (0 != close_lowlevel(this._epollDescriptor))
|
||||||
|
PosixUtilities.throwErrno { d -> RuntimeException("Failed to close epoll descriptor: $d") }
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SocketMetadata : AutoCloseable {
|
class _SocketMetadata : AutoCloseable {
|
||||||
|
@ -44,10 +44,23 @@ internal abstract class NonblockingIcmpSocketImpl : IcmpSocket {
|
|||||||
private val __rSync: CMutex
|
private val __rSync: CMutex
|
||||||
private val __wSync: CMutex
|
private val __wSync: CMutex
|
||||||
private val __refcnt: CloseableRefCounter
|
private val __refcnt: CloseableRefCounter
|
||||||
|
private val __parentProtocol: ParentProtocol
|
||||||
|
|
||||||
|
private enum class ParentProtocol {
|
||||||
|
IPv4 {
|
||||||
|
override fun truncateHeader(orig: UByteArray): UByteArray = orig.sliceArray(((orig[0] and 0xFu).toUInt().toInt() + 15)..<orig.size)
|
||||||
|
},
|
||||||
|
IPv6 {
|
||||||
|
override fun truncateHeader(orig: UByteArray): UByteArray = orig.sliceArray(40..orig.size)
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun truncateHeader(orig: UByteArray): UByteArray
|
||||||
|
}
|
||||||
|
|
||||||
protected constructor(ipv4: CValue<sockaddr_in>) {
|
protected constructor(ipv4: CValue<sockaddr_in>) {
|
||||||
this.__rSync = CMutex()
|
this.__rSync = CMutex()
|
||||||
this.__wSync = CMutex()
|
this.__wSync = CMutex()
|
||||||
|
this.__parentProtocol = ParentProtocol.IPv4
|
||||||
this.__refcnt = CloseableRefCounter("ICMP socket was closed")
|
this.__refcnt = CloseableRefCounter("ICMP socket was closed")
|
||||||
this._socketFd = this.__createSocket(AF_INET, IPPROTO_ICMP, ipv4, CUtilities.sizeOfUI<sockaddr_in>(), "IPv4")
|
this._socketFd = this.__createSocket(AF_INET, IPPROTO_ICMP, ipv4, CUtilities.sizeOfUI<sockaddr_in>(), "IPv4")
|
||||||
}
|
}
|
||||||
@ -55,6 +68,7 @@ internal abstract class NonblockingIcmpSocketImpl : IcmpSocket {
|
|||||||
protected constructor(ipv6: CValue<sockaddr_in6>) {
|
protected constructor(ipv6: CValue<sockaddr_in6>) {
|
||||||
this.__rSync = CMutex()
|
this.__rSync = CMutex()
|
||||||
this.__wSync = CMutex()
|
this.__wSync = CMutex()
|
||||||
|
this.__parentProtocol = ParentProtocol.IPv6
|
||||||
this.__refcnt = CloseableRefCounter("ICMP socket was closed")
|
this.__refcnt = CloseableRefCounter("ICMP socket was closed")
|
||||||
this._socketFd = this.__createSocket(AF_INET6, IPPROTO_ICMPV6, ipv6, CUtilities.sizeOfUI<sockaddr_in6>(), "IPv6")
|
this._socketFd = this.__createSocket(AF_INET6, IPPROTO_ICMPV6, ipv6, CUtilities.sizeOfUI<sockaddr_in6>(), "IPv6")
|
||||||
}
|
}
|
||||||
@ -140,7 +154,7 @@ internal abstract class NonblockingIcmpSocketImpl : IcmpSocket {
|
|||||||
else -> PosixUtilities.throwErrno { d -> RuntimeException("Failed to send message over ICMP socket: $d") }
|
else -> PosixUtilities.throwErrno { d -> RuntimeException("Failed to send message over ICMP socket: $d") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data.sliceArray(((data[0] and 0xFu).toUInt().toInt() + 15)..<data.size)
|
return this.__parentProtocol.truncateHeader(data)
|
||||||
}
|
}
|
||||||
@Suppress("KotlinUnreachableCode")
|
@Suppress("KotlinUnreachableCode")
|
||||||
throw RuntimeException("unreachable")
|
throw RuntimeException("unreachable")
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.landgrafhomyak.bgtu.networks0.icmp.pingSocket_IPv4
|
import ru.landgrafhomyak.bgtu.networks0.icmp.pinger_IPv4
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.Thread
|
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.Thread
|
||||||
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.EpollSocketEventLoop
|
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.EpollSocketEventLoop
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ fun main() {
|
|||||||
val loopThread = Thread(EventLoopRoutine(loop))
|
val loopThread = Thread(EventLoopRoutine(loop))
|
||||||
loopThread.start()
|
loopThread.start()
|
||||||
|
|
||||||
val googleSock = loop.pingSocket_IPv4("8.8.8.8")
|
val googleSock = loop.pinger_IPv4("8.8.8.8")
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
Loading…
Reference in New Issue
Block a user