From 73de26387aad0ad2f87a75b7bb8685811122edad Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 13 Mar 2023 11:21:53 -0400 Subject: [PATCH] Fix P2P receiver not invalidating target on netsplit --- .../phycon/block/DeviceBlockEntity.kt | 8 ++++++++ .../phycon/block/cable/CableBlock.kt | 14 +++++++++----- .../phycon/block/netswitch/SwitchBlockEntity.kt | 17 ++++++++++++++--- .../phycon/block/p2p/P2PReceiverBlockEntity.kt | 16 +++++++++++----- .../terminal/AbstractTerminalBlockEntity.kt | 6 ++++++ .../phycon/frame/NetworkSplitFrame.kt | 8 ++++++++ 6 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/net/shadowfacts/phycon/frame/NetworkSplitFrame.kt diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/DeviceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/DeviceBlockEntity.kt index ba00c76..d224e60 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/DeviceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/DeviceBlockEntity.kt @@ -19,6 +19,7 @@ import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.frame.ARPQueryFrame import net.shadowfacts.phycon.frame.ARPResponseFrame import net.shadowfacts.phycon.frame.BasePacketFrame +import net.shadowfacts.phycon.frame.NetworkSplitFrame import net.shadowfacts.phycon.packet.* import net.shadowfacts.phycon.util.NetworkUtil import java.lang.ref.WeakReference @@ -75,6 +76,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: when (frame) { is ARPQueryFrame -> handleARPQuery(frame) is ARPResponseFrame -> handleARPResponse(frame) + is NetworkSplitFrame -> handleNetworkSplit() is PacketFrame -> { if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) { doHandlePacket(frame.packet) @@ -107,6 +109,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: packetQueue.removeAll(toRemove) } + protected open fun handleNetworkSplit() { + arpTable.clear() + cachedDestination = null + } + override fun sendPacket(packet: Packet) { if (packet.destination.isBroadcast) { send(BasePacketFrame(packet, macAddress, MACAddress.BROADCAST)) @@ -140,6 +147,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: override fun cableDisconnected() { cachedDestination = null + handleNetworkSplit() } open fun tick() { diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/cable/CableBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/block/cable/CableBlock.kt index 6a70116..191a1b1 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/cable/CableBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/cable/CableBlock.kt @@ -2,8 +2,10 @@ package net.shadowfacts.phycon.block.cable import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings import net.minecraft.block.* +import net.minecraft.block.entity.BlockEntity import net.minecraft.entity.player.PlayerEntity import net.minecraft.item.ItemPlacementContext +import net.minecraft.item.ItemStack import net.minecraft.state.StateManager import net.minecraft.state.property.EnumProperty import net.minecraft.util.ActionResult @@ -200,11 +202,13 @@ class CableBlock( override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { super.onBreak(world, pos, state, player) if (!world.isClient) { - // notify devices on either end that the connection was broken (i.e., unset the cached receivers) - val connectedSides = getNetworkConnectedSides(state, world, pos) - for (side in connectedSides) { - val dest = NetworkUtil.findConnectedInterface(world, pos, side) - dest?.cableDisconnected() + world.server?.execute { + // notify devices on either end that the connection was broken (i.e., unset the cached receivers) + val connectedSides = getNetworkConnectedSides(state, world, pos) + for (side in connectedSides) { + val dest = NetworkUtil.findConnectedInterface(world, pos, side) + dest?.cableDisconnected() + } } } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/netswitch/SwitchBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/netswitch/SwitchBlockEntity.kt index a08c5fe..850c1b8 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/netswitch/SwitchBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/netswitch/SwitchBlockEntity.kt @@ -17,6 +17,7 @@ import net.shadowfacts.phycon.api.frame.PacketFrame import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.frame.BasePacketFrame +import net.shadowfacts.phycon.frame.NetworkSplitFrame import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.packet.ItemStackPacket import net.shadowfacts.phycon.util.NetworkUtil @@ -66,12 +67,12 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(PhyBlockE PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir) interfaceForSide(dir).send(frame) } else { - PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, fromItf.side, fromItf.macAddress, frame) flood(frame, fromItf) } } - private fun flood(frame: EthernetFrame, source: Interface) { + private fun flood(frame: EthernetFrame, source: SwitchInterface) { + PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, source.side, source.macAddress, frame) for (itf in interfaces) { if (source == itf) continue itf.send(frame) @@ -86,6 +87,16 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(PhyBlockE } } + private fun cableDisconnected(itf: SwitchInterface) { + macTable.entries.filter { + it.value == itf.side + }.forEach { + macTable.remove(it.key) + } + destinationCache[itf.side.ordinal] = null + flood(NetworkSplitFrame(itf.macAddress), itf) + } + fun tick() { packetsHandledThisTick = 0 @@ -164,7 +175,7 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(PhyBlockE } override fun cableDisconnected() { - switch.get()?.destinationCache?.set(side.ordinal, null) + switch.get()?.cableDisconnected(this) } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/p2p/P2PReceiverBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/p2p/P2PReceiverBlockEntity.kt index 6b3168f..faec4bd 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/p2p/P2PReceiverBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/p2p/P2PReceiverBlockEntity.kt @@ -12,9 +12,11 @@ import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.block.DeviceBlockEntity import net.shadowfacts.phycon.block.FaceDeviceBlock +import net.shadowfacts.phycon.frame.NetworkSplitFrame import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.packet.* import net.shadowfacts.phycon.util.ClientConfigurableDevice +import java.lang.ref.WeakReference /** * @author shadowfacts @@ -50,17 +52,21 @@ class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntit var clientObserver: (() -> Unit)? = null private var isFirstTick = true - // todo: need some way of removing this when there's no network path to the p2p interface - private var targetInventory: Storage? = null + private var targetInventory: WeakReference>? = null override fun handle(packet: Packet) { when (packet) { is PongPacket -> if (packet.source == target) status = Status.OK - is ReadItemStoragePacket -> targetInventory = packet.inventory + is ReadItemStoragePacket -> targetInventory = WeakReference(packet.inventory) is DeviceRemovedPacket -> if (packet.source == target) targetInventory = null } } + override fun handleNetworkSplit() { + super.handleNetworkSplit() + targetInventory = null + } + override fun tick() { super.tick() @@ -74,10 +80,10 @@ class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntit if (target == null) { return null } - if (targetInventory == null) { + if (targetInventory?.get() == null) { sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.SIDED, ipAddress, target!!)) } - return targetInventory + return targetInventory?.get() } private fun updateStatus() { diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/AbstractTerminalBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/AbstractTerminalBlockEntity.kt index 277efee..ddf8d04 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/AbstractTerminalBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/AbstractTerminalBlockEntity.kt @@ -18,6 +18,7 @@ import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.block.DeviceBlockEntity import net.shadowfacts.phycon.component.* +import net.shadowfacts.phycon.frame.NetworkSplitFrame import net.shadowfacts.phycon.packet.* import net.shadowfacts.phycon.util.NetworkUtil import java.lang.ref.WeakReference @@ -69,6 +70,11 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP return null } + override fun handleNetworkSplit() { + super.handleNetworkSplit() + inventoryCache.clear() + } + override fun handle(packet: Packet) { when (packet) { is ReadGroupedInventoryPacket -> handleReadInventory(packet) diff --git a/src/main/kotlin/net/shadowfacts/phycon/frame/NetworkSplitFrame.kt b/src/main/kotlin/net/shadowfacts/phycon/frame/NetworkSplitFrame.kt new file mode 100644 index 0000000..9aac367 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/frame/NetworkSplitFrame.kt @@ -0,0 +1,8 @@ +package net.shadowfacts.phycon.frame + +import net.shadowfacts.phycon.api.util.MACAddress + +/** + * @author shadowfacts + */ +class NetworkSplitFrame(source: MACAddress): BaseFrame(source, MACAddress.BROADCAST)