From fc3716153f3f36277c51eed9bac2ec73141c5129 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 13 Feb 2021 21:28:44 -0500 Subject: [PATCH] Refactor DeviceBlockEntity to only have 1 interface --- .../net/shadowfacts/phycon/api/Interface.java | 3 - .../shadowfacts/phycon/api/PacketSink.java | 5 +- .../shadowfacts/phycon/api/PacketSource.java | 2 +- .../phycon/network/BaseInterface.kt | 53 ------- .../shadowfacts/phycon/network/DeviceBlock.kt | 6 + .../phycon/network/DeviceBlockEntity.kt | 129 +++++------------- .../block/netswitch/SwitchBlockEntity.kt | 26 ++-- .../phycon/network/block/test/DestBlock.kt | 5 - .../network/block/test/DestBlockEntity.kt | 13 +- .../phycon/network/block/test/SourceBlock.kt | 5 - .../network/block/test/SourceBlockEntity.kt | 18 +-- 11 files changed, 61 insertions(+), 204 deletions(-) delete mode 100644 src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt diff --git a/src/main/java/net/shadowfacts/phycon/api/Interface.java b/src/main/java/net/shadowfacts/phycon/api/Interface.java index 6ff71be..6f5ce31 100644 --- a/src/main/java/net/shadowfacts/phycon/api/Interface.java +++ b/src/main/java/net/shadowfacts/phycon/api/Interface.java @@ -1,7 +1,6 @@ package net.shadowfacts.phycon.api; import net.shadowfacts.phycon.api.frame.EthernetFrame; -import net.shadowfacts.phycon.api.packet.Packet; import net.shadowfacts.phycon.api.util.MACAddress; import org.jetbrains.annotations.NotNull; @@ -17,6 +16,4 @@ public interface Interface { void send(@NotNull EthernetFrame frame); -// void send(@NotNull Packet packet); - } diff --git a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java index b8ce2f1..fb5b299 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java +++ b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java @@ -8,9 +8,6 @@ import org.jetbrains.annotations.NotNull; */ public interface PacketSink extends NetworkDevice { - @NotNull - Iterable getDeviceInterfaces(); - - void handle(@NotNull Packet packet, @NotNull Interface itf); + void handle(@NotNull Packet packet); } diff --git a/src/main/java/net/shadowfacts/phycon/api/PacketSource.java b/src/main/java/net/shadowfacts/phycon/api/PacketSource.java index c7a8d0d..f1ccfc7 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PacketSource.java +++ b/src/main/java/net/shadowfacts/phycon/api/PacketSource.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; // todo: does PacketSource actually need to extend NetworkDevice? public interface PacketSource extends NetworkDevice { // todo: better name for this - void sendPacket(@NotNull Packet packet, @Nullable Interface itf); + void sendPacket(@NotNull Packet packet); // void sendToAll(@NotNull Packet packet); // diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt b/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt deleted file mode 100644 index b1f5a53..0000000 --- a/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt +++ /dev/null @@ -1,53 +0,0 @@ -package net.shadowfacts.phycon.network - -import net.shadowfacts.phycon.api.frame.EthernetFrame -import net.shadowfacts.phycon.api.Interface -import net.shadowfacts.phycon.api.PacketSink -import net.shadowfacts.phycon.api.packet.Packet -import net.shadowfacts.phycon.api.util.MACAddress -import net.shadowfacts.phycon.network.frame.BaseFrame -import java.lang.ref.WeakReference - -/** - * @author shadowfacts - */ -open class BaseInterface( - var macAddress: MACAddress, - private val delegate: WeakReference -): Interface { - - constructor(delegate: InterfaceDelegate): this(MACAddress.random(), WeakReference(delegate)) - - override fun getMACAddress(): MACAddress { - return macAddress - } - - override fun receive(frame: EthernetFrame) { - delegate.get()?.handle(frame, this) - } - - override fun send(frame: EthernetFrame) { - delegate.get()?.findDestination(this)?.receive(frame) - } - -// override fun send(packet: Packet) { -// delegate.get()?.findDestination(this)?.also { -// it.receive(BaseFrame(packet, this.macAddress, it.macAddress)) -// } -// } - - override fun equals(other: Any?): Boolean { - return (other as? BaseInterface)?.macAddress == macAddress - } - - override fun hashCode(): Int { - return macAddress.hashCode() - } - -} - -interface InterfaceDelegate { - fun findDestination(fromItf: Interface): Interface? - - fun handle(frame: EthernetFrame, fromItf: Interface) -} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt index f9af942..4aef5e1 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt @@ -3,7 +3,9 @@ package net.shadowfacts.phycon.network import net.minecraft.block.BlockState import net.minecraft.entity.player.PlayerEntity import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction import net.minecraft.world.World +import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.block.BlockWithEntity @@ -12,6 +14,10 @@ import net.shadowfacts.phycon.block.BlockWithEntity */ abstract class DeviceBlock(settings: Settings): BlockWithEntity(settings), NetworkComponentBlock { + override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { + return getBlockEntity(world, pos)!! + } + override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { super.onBreak(world, pos, state, player) getBlockEntity(world, pos)!!.onBreak() diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt index f36720a..819fe4d 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt @@ -30,61 +30,61 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), Tickable, PacketSink, PacketSource, - InterfaceDelegate { + Interface { companion object { private const val ARP_RETRY_TIMEOUT = 200 } -// var macAddress: MACAddress = MACAddress.random() -// protected set + var macAddress: MACAddress = MACAddress.random() + protected set var ipAddress: IPAddress = IPAddress.random() protected set - open val interfaces: List = listOf() -// abstract val itf: BaseInterface - private val arpTable = mutableMapOf() private val packetQueue = LinkedList() protected var counter: Long = 0 override fun getIPAddress() = ipAddress + override fun getMACAddress() = macAddress - override fun getDeviceInterfaces() = interfaces + abstract override fun handle(packet: Packet) - abstract override fun handle(packet: Packet, itf: Interface) + override fun send(frame: EthernetFrame) { + findDestination()?.receive(frame) + } - override fun handle(frame: EthernetFrame, fromItf: Interface) { - println("$this ($ipAddress, ${fromItf.macAddress}) received frame from ${frame.source}: $frame") + override fun receive(frame: EthernetFrame) { + println("$this ($ipAddress, ${macAddress}) received frame from ${frame.source}: $frame") when (frame) { - is ARPQueryFrame -> handleARPQuery(frame, fromItf) - is ARPResponseFrame -> handleARPResponse(frame, fromItf) + is ARPQueryFrame -> handleARPQuery(frame) + is ARPResponseFrame -> handleARPResponse(frame) is PacketFrame -> { if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) { - handle(frame.packet, fromItf) + handle(frame.packet) } } } } - private fun handleARPQuery(frame: ARPQueryFrame, fromItf: Interface) { + private fun handleARPQuery(frame: ARPQueryFrame) { println("$this ($ipAddress) received ARP query for ${frame.queryIP}") arpTable[frame.sourceIP] = frame.source if (frame.queryIP == ipAddress) { - println("$this ($ipAddress) sending ARP response to ${frame.source} with ${fromItf.macAddress}") - fromItf.send(ARPResponseFrame(ipAddress, fromItf.macAddress, frame.source)) + println("$this ($ipAddress) sending ARP response to ${frame.source} with $macAddress") + send(ARPResponseFrame(ipAddress, macAddress, frame.source)) } } - private fun handleARPResponse(frame: ARPResponseFrame, fromItf: Interface) { + private fun handleARPResponse(frame: ARPResponseFrame) { arpTable[frame.query] = frame.source println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}") - packetQueue.removeIf { (packet, itf, _) -> + packetQueue.removeIf { (packet, _) -> if (packet.destination == frame.query) { - itf.send(BasePacketFrame(packet, itf.macAddress, frame.source)) + send(BasePacketFrame(packet, macAddress, frame.source)) true } else { false @@ -92,79 +92,19 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), } } -// protected abstract fun handlePacket(packet: Packet, itf: Interface) -// -// protected open fun acceptsPacket(packet: Packet, itf: Interface): Boolean { -// return when (packet.destination.type) { -// MACAddress.Type.BROADCAST -> true -// MACAddress.Type.UNICAST -> itf.macAddress == packet.destination -// MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet) -// } -// } - -// open fun acceptsMulticastPacket(packet: Packet): Boolean { -// return false -// } - - fun sendPacket(packet: Packet) { - sendPacket(packet, null) - } - - override fun sendPacket(packet: Packet, itf: Interface?) { - @Suppress("NAME_SHADOWING") var itf = itf - if (itf == null) { - if (interfaces.size == 1) { - itf = interfaces.first() - } else { - throw RuntimeException("Cannot send packet from device with multiple interfaces without explicitly specifying interface") - } - } - + override fun sendPacket(packet: Packet) { val cached = arpTable[packet.destination] if (cached != null) { - itf.send(BasePacketFrame(packet, itf.macAddress, cached)) + send(BasePacketFrame(packet, macAddress, cached)) } else { -// packetQueue.add(packet to itf) - packetQueue.add(PendingPacket(packet, itf, counter)) + packetQueue.add(PendingPacket(packet, counter)) println("$this ($ipAddress) sending ARP query for ${packet.destination}") - itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.macAddress)) - // after sending an ARP query we expect to have received a response and added an entry to our ARP table - // todo: this makes the assumption that packets are sent the entire way synchronously, and then a response - // is immediately sent and forwarded also synchronously -// cached = arpTable[packet.destination] + send(ARPQueryFrame(packet.destination, ipAddress, macAddress)) } } -// fun findMACAddressFor(ipAddress: IPAddress): MACAddress? { -// if (arpTable.containsKey(ipAddress)) { -// return arpTable[ipAddress] -// } else { -// -// } -// } - -// override fun sendToSingle(packet: Packet) { -// val destinations = NetworkUtil.findDestinations(world!!, pos) -// if (destinations.size != 1) { -// // todo: handle this better -// println("Can't send packet, multiple destinations available: $destinations") -// return -// } -// send(packet)) -// } - -// override fun sendToAll(packet: Packet) { -// sendToAll(packet, NetworkUtil.findDestinations(world!!, pos)) -// } -// -// override fun sendToAll(packet: Packet, destinations: Iterable) { -// destinations.forEach { -// it.handle(packet) -// } -// } - - override fun findDestination(fromItf: Interface): Interface? { + open fun findDestination(): Interface? { val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos) if (sides.size != 1) { throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side") @@ -177,12 +117,12 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), counter++ packetQueue.removeIf { entry -> - val (packet, itf, timestamp) = entry + val (packet, timestamp) = entry if (arpTable.containsKey(packet.destination)) { - itf.send(BasePacketFrame(packet, itf.macAddress, arpTable[packet.destination]!!)) + send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!)) true } else if (counter - timestamp >= ARP_RETRY_TIMEOUT) { - itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.macAddress)) + send(ARPQueryFrame(packet.destination, ipAddress, macAddress)) entry.timestamp = counter // todo: should there be a retry counter? true @@ -195,31 +135,25 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), override fun toTag(tag: CompoundTag): CompoundTag { tag.putInt("IPAddress", ipAddress.address) -// tag.putLong("MACAddress", macAddress.address) - tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) + tag.putLong("MACAddress", macAddress.address) return super.toTag(tag) } override fun fromTag(state: BlockState, tag: CompoundTag) { super.fromTag(state, tag) ipAddress = IPAddress(tag.getInt("IPAddress")) - // todo: what happens if the defined number of ports changes between mod versions? - tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> - interfaces[i].macAddress = MACAddress(l) - } + macAddress = MACAddress(tag.getLong("MACAddress")) } override fun toClientTag(tag: CompoundTag): CompoundTag { tag.putInt("IPAddress", ipAddress.address) - tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) + tag.putLong("MACAddress", macAddress.address) return tag } override fun fromClientTag(tag: CompoundTag) { ipAddress = IPAddress(tag.getInt("IPAddress")) - tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> - interfaces[i].macAddress = MACAddress(l) - } + macAddress = MACAddress(tag.getLong("MACAddress")) } fun onBreak() { @@ -228,7 +162,6 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), data class PendingPacket( val packet: Packet, - val sourceItf: Interface, var timestamp: Long, ) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt index 8b391b5..af14031 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt @@ -8,27 +8,23 @@ import net.minecraft.util.Tickable import net.minecraft.util.math.Direction import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.frame.EthernetFrame -import net.shadowfacts.phycon.api.packet.Packet -import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.init.PhyBlockEntities -import net.shadowfacts.phycon.network.BaseInterface -import net.shadowfacts.phycon.network.InterfaceDelegate import net.shadowfacts.phycon.network.NetworkUtil +import java.lang.ref.WeakReference /** * @author shadowfacts */ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), BlockEntityClientSerializable, - InterfaceDelegate, Tickable { companion object { var SWITCHING_CAPACITY = 256 } - val interfaces = Direction.values().map { SwitchInterface(it, this) } + val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) } private val macTable = mutableMapOf() private var packetsHandledThisTick = 0 @@ -69,7 +65,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), return interfaces.find { it.side == side }!! } - override fun handle(frame: EthernetFrame, fromItf: Interface) { + private fun handle(frame: EthernetFrame, fromItf: Interface) { val itfSide = (fromItf as SwitchInterface).side macTable[frame.source] = itfSide @@ -90,7 +86,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), } } - override fun findDestination(fromItf: Interface): Interface? { + private fun findDestination(fromItf: Interface): Interface? { val side = (fromItf as SwitchInterface).side return NetworkUtil.findConnectedInterface(world!!, pos, side) } @@ -122,8 +118,20 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), } } - class SwitchInterface(val side: Direction, delegate: InterfaceDelegate): BaseInterface(delegate) { + class SwitchInterface( + val side: Direction, + val switch: WeakReference, + @JvmField var macAddress: MACAddress, + ): Interface { + override fun getMACAddress() = macAddress + override fun receive(frame: EthernetFrame) { + switch.get()?.handle(frame, this) + } + + override fun send(frame: EthernetFrame) { + switch.get()?.findDestination(this)?.receive(frame) + } } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt index 66e1a81..10ac59c 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt @@ -12,7 +12,6 @@ import net.minecraft.util.math.Direction import net.minecraft.world.BlockView import net.minecraft.world.World import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.network.DeviceBlock import java.util.* @@ -33,10 +32,6 @@ class DestBlock: DeviceBlock(Settings.of(Material.METAL)) { return EnumSet.allOf(Direction::class.java) } - override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { - return getBlockEntity(world, pos)!!.interfaces.first() - } - override fun onUse( blockState: BlockState?, world: World, diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt index b60feb8..3ea52b3 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt @@ -2,10 +2,8 @@ package net.shadowfacts.phycon.network.block.test import net.minecraft.util.math.Direction import net.shadowfacts.phycon.api.Interface -import net.shadowfacts.phycon.api.frame.EthernetFrame import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.init.PhyBlockEntities -import net.shadowfacts.phycon.network.BaseInterface import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.NetworkUtil @@ -14,18 +12,11 @@ import net.shadowfacts.phycon.network.NetworkUtil */ class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) { - override val interfaces = listOf(BaseInterface(this)) - - override fun handle(packet: Packet, itf: Interface) { + override fun handle(packet: Packet) { println("$this ($ipAddress) received packet: $packet") } - override fun handle(frame: EthernetFrame, fromItf: Interface) { -// println("dest ${fromItf.macAddress} received frame from ${frame.source}") - super.handle(frame, fromItf) - } - - override fun findDestination(fromItf: Interface): Interface? { + override fun findDestination(): Interface? { for (dir in Direction.values()) { val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) if (itf != null) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt index 21f0f82..3ac037b 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt @@ -8,7 +8,6 @@ import net.minecraft.util.math.Direction import net.minecraft.world.BlockView import net.minecraft.world.World import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.network.DeviceBlock import java.util.* @@ -29,8 +28,4 @@ class SourceBlock: DeviceBlock(Settings.of(Material.METAL)) { return EnumSet.allOf(Direction::class.java) } - override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { - return getBlockEntity(world, pos)!!.interfaces.first() - } - } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt index 2aaeb29..7371a71 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt @@ -3,41 +3,29 @@ package net.shadowfacts.phycon.network.block.test import net.minecraft.util.Tickable import net.minecraft.util.math.Direction import net.shadowfacts.phycon.api.Interface -import net.shadowfacts.phycon.api.frame.EthernetFrame import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.init.PhyBlockEntities -import net.shadowfacts.phycon.network.BaseInterface import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.NetworkUtil -import net.shadowfacts.phycon.network.frame.BaseFrame /** * @author shadowfacts */ class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable { - override val interfaces = listOf(BaseInterface(this)) - - override fun handle(packet: Packet, itf: Interface) { + override fun handle(packet: Packet) { TODO("Not yet implemented") } - override fun handle(frame: EthernetFrame, fromItf: Interface) { -// println("${fromItf.macAddress} received frame from ${frame.source}") - super.handle(frame, fromItf) - } - -// var counter = 0 - override fun tick() { super.tick() if (!world!!.isClient && counter % 40 == 0L) { - sendPacket(TestPacket(ipAddress, IPAddress(67, 237, 255, 168))) + sendPacket(TestPacket(ipAddress, IPAddress(170, 171, 101, 168))) } } - override fun findDestination(fromItf: Interface): Interface? { + override fun findDestination(): Interface? { for (dir in Direction.values()) { val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) if (itf != null) {