diff --git a/src/main/java/li/cil/oc2/api/inet/LayerParameters.java b/src/main/java/li/cil/oc2/api/inet/LayerParameters.java index 1f35bf64..ca9e19b6 100644 --- a/src/main/java/li/cil/oc2/api/inet/LayerParameters.java +++ b/src/main/java/li/cil/oc2/api/inet/LayerParameters.java @@ -2,7 +2,9 @@ package li.cil.oc2.api.inet; import net.minecraft.nbt.Tag; +import java.util.Optional; + public interface LayerParameters { - Tag getSavedState(); + Optional getSavedState(); InternetManager getInternetManager(); } diff --git a/src/main/java/li/cil/oc2/api/inet/provider/InternetProvider.java b/src/main/java/li/cil/oc2/api/inet/provider/InternetProvider.java index 6d2cce2d..96788166 100644 --- a/src/main/java/li/cil/oc2/api/inet/provider/InternetProvider.java +++ b/src/main/java/li/cil/oc2/api/inet/provider/InternetProvider.java @@ -29,7 +29,7 @@ import li.cil.oc2.api.inet.layer.LinkLocalLayer; public interface InternetProvider { /** - * This method should provide and implementation of {@link LinkLocalLayer} interface and not fail. + * This method should provide an implementation of {@link LinkLocalLayer} interface. * It will be called once for each loaded internet card. * * @return an implementation of {@link LinkLocalLayer} interface diff --git a/src/main/java/li/cil/oc2/common/Constants.java b/src/main/java/li/cil/oc2/common/Constants.java index b4fcdeec..42cb51c1 100644 --- a/src/main/java/li/cil/oc2/common/Constants.java +++ b/src/main/java/li/cil/oc2/common/Constants.java @@ -28,6 +28,7 @@ public final class Constants { public static final String MOD_TAG_NAME = API.MOD_ID; public static final String ITEMS_TAG_NAME = "items"; public static final String ENERGY_TAG_NAME = "energy"; + public static final String INTERNET_ADAPTER_TAG_NAME = "InternetAdapter"; /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/blockentity/InternetGateWayBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/InternetGateWayBlockEntity.java index c84eb808..d82eabfa 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/InternetGateWayBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/InternetGateWayBlockEntity.java @@ -19,7 +19,6 @@ import li.cil.oc2.common.inet.InternetManagerImpl; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.EndTag; import net.minecraft.nbt.Tag; import net.minecraft.world.level.block.state.BlockState; import org.apache.logging.log4j.LogManager; @@ -34,7 +33,6 @@ public class InternetGateWayBlockEntity extends ModBlockEntity implements Networ private InternetConnection internetConnection; - private static final String STATE_TAG = "internet_adapter"; private Tag internetState; private final FixedEnergyStorage energy = new FixedEnergyStorage(Config.gatewayEnergyStorage); @@ -43,18 +41,14 @@ public class InternetGateWayBlockEntity extends ModBlockEntity implements Networ super(BlockEntities.INTERNET_GATEWAY.get(), pos, state); inboundQueue = new ArrayDeque<>(); outboundQueue = new ArrayDeque<>(); - internetState = EndTag.INSTANCE; + internetState = null; setNeedsLevelUnloadEvent(); } @Override public void load(CompoundTag tag) { super.load(tag); - if (tag.contains(STATE_TAG)) { - internetState = tag.get(STATE_TAG); - } else { - internetState = EndTag.INSTANCE; - } + internetState = tag.get(Constants.INTERNET_ADAPTER_TAG_NAME); energy.deserializeNBT(tag.getCompound(Constants.ENERGY_TAG_NAME)); } @@ -62,7 +56,8 @@ public class InternetGateWayBlockEntity extends ModBlockEntity implements Networ public void saveAdditional(CompoundTag tag) { super.saveAdditional(tag); if (internetConnection != null) { - internetConnection.saveAdapterState().ifPresent(adapterState -> tag.put(STATE_TAG, adapterState)); + internetConnection.saveAdapterState() + .ifPresent(adapterState -> tag.put(Constants.INTERNET_ADAPTER_TAG_NAME, adapterState)); } tag.put(Constants.ENERGY_TAG_NAME, energy.serializeNBT()); LOGGER.info("State saved"); @@ -70,7 +65,8 @@ public class InternetGateWayBlockEntity extends ModBlockEntity implements Networ @Override protected void loadServer() { - InternetManagerImpl.getInstance().ifPresent(internetManager -> internetConnection = internetManager.connect(this, internetState)); + InternetManagerImpl.getInstance() + .ifPresent(internetManager -> internetConnection = internetManager.connect(this, internetState)); if (internetConnection != null) { LOGGER.info("Connected to the internet"); } else { @@ -103,7 +99,7 @@ public class InternetGateWayBlockEntity extends ModBlockEntity implements Networ } return hasEnough; } - + @Override public void sendEthernetFrame(byte[] frame) { LOGGER.info("Got inbound packet"); diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/item/InternetCardDevice.java b/src/main/java/li/cil/oc2/common/bus/device/vm/item/InternetCardDevice.java index 53918fe4..9f1d5410 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/vm/item/InternetCardDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/item/InternetCardDevice.java @@ -3,6 +3,7 @@ package li.cil.oc2.common.bus.device.vm.item; import li.cil.oc2.api.bus.device.vm.VMDeviceLoadResult; import li.cil.oc2.api.bus.device.vm.context.VMContext; import li.cil.oc2.api.capabilities.NetworkInterface; +import li.cil.oc2.common.Constants; import li.cil.oc2.common.inet.InternetAdapter; import li.cil.oc2.common.inet.InternetConnection; import li.cil.oc2.common.inet.InternetManagerImpl; @@ -15,13 +16,12 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.Objects; +import java.util.Optional; public final class InternetCardDevice extends AbstractNetworkInterfaceDevice { private static final Logger LOGGER = LogManager.getLogger(); - private static final String ADAPTER_SUBTAG = "InternetAdapter"; - /////////////////////////////////////////////////////////////// private InternetConnection internetConnection = null; @@ -37,11 +37,9 @@ public final class InternetCardDevice extends AbstractNetworkInterfaceDevice { private void openInternetAccess() { LOGGER.debug("Connect internet card"); closeInternetAccess(); - final Tag savedState = internetAdapterState; - assert savedState != null; final InternetAdapter internetAdapter = new InternetAdapterImpl(getNetworkInterface()); InternetManagerImpl.getInstance() - .ifPresent(internetManager -> internetConnection = internetManager.connect(internetAdapter, savedState)); + .ifPresent(internetManager -> internetConnection = internetManager.connect(internetAdapter, internetAdapterState)); } private void closeInternetAccess() { @@ -57,7 +55,7 @@ public final class InternetCardDevice extends AbstractNetworkInterfaceDevice { @Override public void deserializeNBT(final CompoundTag tag) { super.deserializeNBT(tag); - internetAdapterState = Objects.requireNonNullElse(tag.get(ADAPTER_SUBTAG), EndTag.INSTANCE); + internetAdapterState = tag.get(Constants.INTERNET_ADAPTER_TAG_NAME); } @Override @@ -66,7 +64,11 @@ public final class InternetCardDevice extends AbstractNetworkInterfaceDevice { final InternetConnection internetConnection = this.internetConnection; if (internetConnection != null) { internetConnection.saveAdapterState() - .ifPresent(adapterState -> tag.put(ADAPTER_SUBTAG, adapterState)); + .ifPresent(adapterState -> { + tag.put(Constants.INTERNET_ADAPTER_TAG_NAME, adapterState); + // TODO: not sure, if this is meaningful + internetAdapterState = adapterState; + }); } return tag; } diff --git a/src/main/java/li/cil/oc2/common/inet/DefaultLinkLocalLayer.java b/src/main/java/li/cil/oc2/common/inet/DefaultLinkLocalLayer.java index 7841243f..9b06ae08 100644 --- a/src/main/java/li/cil/oc2/common/inet/DefaultLinkLocalLayer.java +++ b/src/main/java/li/cil/oc2/common/inet/DefaultLinkLocalLayer.java @@ -53,25 +53,26 @@ public final class DefaultLinkLocalLayer implements LinkLocalLayer { /////////////////////////////////////////////////// public DefaultLinkLocalLayer(final LayerParameters layerParameters, final NetworkLayer networkLayer) { - final Tag tag = layerParameters.getSavedState(); - if (tag instanceof CompoundTag layerState) { - final String ipAddressString = layerState.getString(IPv4_ADDRESS_TAG); - if (!ipAddressString.isEmpty()) { - try { - myIpV4Address = InetUtils.parseIpv4Address(ipAddressString); - } catch (final AddressParseException exception) { - LOGGER.error("Failed to parse internet adapter IPv4 address", exception); + layerParameters.getSavedState().ifPresent(tag -> { + if (tag instanceof CompoundTag layerState) { + final String ipAddressString = layerState.getString(IPv4_ADDRESS_TAG); + if (!ipAddressString.isEmpty()) { + try { + myIpV4Address = InetUtils.parseIpv4Address(ipAddressString); + } catch (final AddressParseException exception) { + LOGGER.error("Failed to parse internet adapter IPv4 address", exception); + } + } + final String macAddressString = layerState.getString(MAC_ADDRESS_TAG); + if (!macAddressString.isEmpty()) { + try { + myMacAddress = InetUtils.parseMacAddress(macAddressString); + } catch (final AddressParseException exception) { + LOGGER.error("Failed to parse internet adapter MAC address from NBT", exception); + } } } - final String macAddressString = layerState.getString(MAC_ADDRESS_TAG); - if (!macAddressString.isEmpty()) { - try { - myMacAddress = InetUtils.parseMacAddress(macAddressString); - } catch (final AddressParseException exception) { - LOGGER.error("Failed to parse internet adapter MAC address from NBT", exception); - } - } - } + }); this.networkLayer = networkLayer; } diff --git a/src/main/java/li/cil/oc2/common/inet/DefaultSessionLayer.java b/src/main/java/li/cil/oc2/common/inet/DefaultSessionLayer.java index c0b73484..6f04d68e 100644 --- a/src/main/java/li/cil/oc2/common/inet/DefaultSessionLayer.java +++ b/src/main/java/li/cil/oc2/common/inet/DefaultSessionLayer.java @@ -16,9 +16,11 @@ import java.net.InetAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; +import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; public final class DefaultSessionLayer implements SessionLayer { private static final Logger LOGGER = LogManager.getLogger(); @@ -59,14 +61,7 @@ public final class DefaultSessionLayer implements SessionLayer { return; } - while (true) { - final Session session = readySessions.getToRead().poll(); - if (session == null) { - break; - } - if (session.isClosed()) { - continue; - } + final boolean somethingRead = processQueue(readySessions.getToRead(), session -> { if (session instanceof DatagramSession datagramSession) { LOGGER.info("Datagram received"); final DatagramChannel channel = getChannel(datagramSession); @@ -75,18 +70,47 @@ public final class DefaultSessionLayer implements SessionLayer { assert datagram != null; final SocketAddress address = channel.receive(datagram); if (address == null) { - return; + return false; } if (Config.useSynchronisedNAT && !address.equals(datagramSession.getDestination())) { - return; + return false; } datagram.flip(); - } catch (IOException e) { - LOGGER.error("Trying to read datagram socket", e); + return true; + } catch (final IOException exception) { + LOGGER.error("Trying to read datagram socket", exception); } LOGGER.info("Datagram received"); + } else if (session instanceof StreamSession streamSession) { + LOGGER.info("Stream received"); + final SocketChannel channel = getChannel(streamSession); + try { + final ByteBuffer stream = receiver.receive(streamSession); + assert stream != null; + final int read = channel.read(stream); + if (read != 0) { + // some data still remaining in socket, read it later + readySessions.getToRead().add(streamSession); + } + return true; + } catch (final IOException exception) { + LOGGER.error("Trying to read stream socket", exception); + } } + return false; + }); + if (somethingRead) { + return; } + + processQueue(readySessions.getToConnect(), session -> { + if (session instanceof StreamSession streamSession) { + receiver.receive(streamSession); + streamSession.connect(); + return true; + } + return false; + }); } @Override @@ -120,7 +144,7 @@ public final class DefaultSessionLayer implements SessionLayer { LOGGER.info("Send datagram"); final DatagramChannel channel = getChannel(datagramSession); assert data != null; - int sent = channel.send(data, session.getDestination()); + channel.send(data, session.getDestination()); break; } case EXPIRED: { @@ -161,6 +185,21 @@ public final class DefaultSessionLayer implements SessionLayer { } } + private boolean processQueue(final Queue queue, final Function action) { + while (true) { + final Session session = queue.poll(); + if (session == null) { + return false; + } + if (session.isClosed()) { + continue; + } + if (action.apply(session)) { + return true; + } + } + } + private void closeSession(final Session session) { try { getChannel(session).close(); diff --git a/src/main/java/li/cil/oc2/common/inet/InetUtils.java b/src/main/java/li/cil/oc2/common/inet/InetUtils.java index 92e69b6f..6a4ffaca 100644 --- a/src/main/java/li/cil/oc2/common/inet/InetUtils.java +++ b/src/main/java/li/cil/oc2/common/inet/InetUtils.java @@ -3,14 +3,13 @@ package li.cil.oc2.common.inet; import li.cil.oc2.api.inet.LayerParameters; import li.cil.oc2.api.inet.layer.LinkLocalLayer; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.EndTag; import net.minecraft.nbt.Tag; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; -import java.util.Objects; +import java.util.Optional; import java.util.function.Function; public final class InetUtils { @@ -42,16 +41,16 @@ public final class InetUtils { } public static short transportRfc1071Checksum( - final ByteBuffer buffer, - final int srcIpAddress, - final int dstIpAddress, - final byte protocol + final ByteBuffer buffer, + final int srcIpAddress, + final int dstIpAddress, + final byte protocol ) { final int size = buffer.remaining(); final int checksumPart = bufferChecksum(buffer, size); final int checksum = checksumPart + Byte.toUnsignedInt(protocol) + size + - (srcIpAddress >>> 16) + (srcIpAddress & 0xFFFF) + - (dstIpAddress >>> 16) + (dstIpAddress & 0xFFFF); + (srcIpAddress >>> 16) + (srcIpAddress & 0xFFFF) + + (dstIpAddress >>> 16) + (dstIpAddress & 0xFFFF); return finishChecksum(checksum); } @@ -66,10 +65,10 @@ public final class InetUtils { public static InetAddress toJavaInetAddress(final int ipAddress) { final byte[] bytes = new byte[]{ - (byte) (ipAddress >>> 24), - (byte) (ipAddress >>> 16), - (byte) (ipAddress >>> 8), - (byte) (ipAddress) + (byte) (ipAddress >>> 24), + (byte) (ipAddress >>> 16), + (byte) (ipAddress >>> 8), + (byte) (ipAddress) }; return getInetAddressByBytes(bytes); } @@ -124,7 +123,7 @@ public final class InetUtils { byteToHex(builder, (byte) prefix); for (int i = 3; i >= 0; --i) { builder.append(':'); - byteToHex(builder, (byte) (address >>> (8*i))); + byteToHex(builder, (byte) (address >>> (8 * i))); } } @@ -160,7 +159,7 @@ public final class InetUtils { public static int javaInetAddressToIpAddress(final Inet4Address address) { final byte[] bytes = address.getAddress(); return (Byte.toUnsignedInt(bytes[0]) << 24) | (Byte.toUnsignedInt(bytes[1]) << 16) - | (Byte.toUnsignedInt(bytes[2]) << 8) | Byte.toUnsignedInt(bytes[3]); + | (Byte.toUnsignedInt(bytes[2]) << 8) | Byte.toUnsignedInt(bytes[3]); } public static int indexOf(final CharSequence string, final char character, final int start) { @@ -222,7 +221,7 @@ public final class InetUtils { final short prefix = (short) (first << 8 | parseMacAddressByte(string, 3)); int address = 0; for (int i = 0; i < 4; ++i) { - final int pos = i*3 + 5; + final int pos = i * 3 + 5; if (string.charAt(pos) != ':') { throw illegalDelimiter(string, pos); } @@ -282,13 +281,10 @@ public final class InetUtils { } public static LayerParameters nextLayerParameters(final LayerParameters layerParameters, final String layerName) { - final Tag currentLayerState = layerParameters.getSavedState(); - final Tag nextLayerState; - if (currentLayerState instanceof CompoundTag tag) { - nextLayerState = Objects.requireNonNullElse(tag.get(layerName), EndTag.INSTANCE); - } else { - nextLayerState = EndTag.INSTANCE; - } + final Optional nextLayerState = layerParameters.getSavedState() + .flatMap(currentLayerState -> (currentLayerState instanceof CompoundTag tag) ? + Optional.ofNullable(tag.get(layerName)) : + Optional.empty()); return new LayerParametersImpl(nextLayerState, layerParameters.getInternetManager()); } } diff --git a/src/main/java/li/cil/oc2/common/inet/InternetManagerImpl.java b/src/main/java/li/cil/oc2/common/inet/InternetManagerImpl.java index e1bea9c1..43b74df2 100644 --- a/src/main/java/li/cil/oc2/common/inet/InternetManagerImpl.java +++ b/src/main/java/li/cil/oc2/common/inet/InternetManagerImpl.java @@ -69,8 +69,8 @@ public final class InternetManagerImpl implements InternetManager { return task; } - public InternetConnection connect(final InternetAdapter internetAdapter, final Tag savedState) { - final LayerParameters layerParameters = new LayerParametersImpl(savedState, this); + public InternetConnection connect(final InternetAdapter internetAdapter, @Nullable final Tag savedState) { + final LayerParameters layerParameters = new LayerParametersImpl(Optional.ofNullable(savedState), this); final InternetConnectionImpl internetConnection = new InternetConnectionImpl(internetAdapter, internetProvider.provideInternet(layerParameters)); connections.add(internetConnection); @@ -116,7 +116,10 @@ public final class InternetManagerImpl implements InternetManager { final List connectionsToProcess ) { runTasks(); - connectionsToStop.forEach(InternetConnectionImpl::stop); + connectionsToStop.forEach(connection -> { + LOGGER.debug("Revoked internet access"); + connection.ethernet.onStop(); + }); connectionsToProcess.forEach(InternetConnectionImpl::process); } diff --git a/src/main/java/li/cil/oc2/common/inet/LayerParametersImpl.java b/src/main/java/li/cil/oc2/common/inet/LayerParametersImpl.java index c75e7887..6317082e 100644 --- a/src/main/java/li/cil/oc2/common/inet/LayerParametersImpl.java +++ b/src/main/java/li/cil/oc2/common/inet/LayerParametersImpl.java @@ -4,5 +4,7 @@ import li.cil.oc2.api.inet.LayerParameters; import li.cil.oc2.api.inet.InternetManager; import net.minecraft.nbt.Tag; -public record LayerParametersImpl(Tag getSavedState, InternetManager getInternetManager) implements LayerParameters { +import java.util.Optional; + +public record LayerParametersImpl(Optional getSavedState, InternetManager getInternetManager) implements LayerParameters { }