Simplifications, bugfixes and TCP once again

This commit is contained in:
ktlo
2022-04-06 15:21:52 +03:00
committed by logan
parent db5fb40243
commit d37406244e
10 changed files with 118 additions and 76 deletions

View File

@@ -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<Tag> getSavedState();
InternetManager getInternetManager();
}

View File

@@ -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

View File

@@ -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";
///////////////////////////////////////////////////////////////////

View File

@@ -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");

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Session> queue, final Function<Session, Boolean> 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();

View File

@@ -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<Tag> nextLayerState = layerParameters.getSavedState()
.flatMap(currentLayerState -> (currentLayerState instanceof CompoundTag tag) ?
Optional.ofNullable(tag.get(layerName)) :
Optional.empty());
return new LayerParametersImpl(nextLayerState, layerParameters.getInternetManager());
}
}

View File

@@ -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<InternetConnectionImpl> connectionsToProcess
) {
runTasks();
connectionsToStop.forEach(InternetConnectionImpl::stop);
connectionsToStop.forEach(connection -> {
LOGGER.debug("Revoked internet access");
connection.ethernet.onStop();
});
connectionsToProcess.forEach(InternetConnectionImpl::process);
}

View File

@@ -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<Tag> getSavedState, InternetManager getInternetManager) implements LayerParameters {
}