From fcd985b570013802b7c0287794b5eaf74e1964f3 Mon Sep 17 00:00:00 2001 From: Captain ALM Date: Tue, 14 Jun 2022 16:35:14 +0100 Subject: [PATCH] Finish implementing fragment verification. --- .idea/vcs.xml | 6 ++ .../lib/calmnet/packet/FragmentReceiver.java | 58 +++++++++++++++- .../lib/calmnet/packet/FragmentSender.java | 66 +++++++++++++++++-- 3 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..c8397c9 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/com/captainalm/lib/calmnet/packet/FragmentReceiver.java b/src/com/captainalm/lib/calmnet/packet/FragmentReceiver.java index b8a2476..f914194 100644 --- a/src/com/captainalm/lib/calmnet/packet/FragmentReceiver.java +++ b/src/com/captainalm/lib/calmnet/packet/FragmentReceiver.java @@ -25,6 +25,7 @@ public final class FragmentReceiver { private PacketLoader packetLoader; private IPacketFactory packetFactory; private boolean verifyResponses = false; + private boolean makeSureSendDataVerified = false; /** * Constructs a new FragmentReceiver with the specified {@link PacketLoader} and {@link IPacketFactory}. @@ -262,12 +263,36 @@ public final class FragmentReceiver { /** * Sets whether responses should be verified. + * If set to false, {@link #setSentDataWillBeAllVerified(boolean)} will be set to false too. * * @param state If responses should be verified. */ public void setResponseVerification(boolean state) { synchronized (slock) { verifyResponses = state; + if (makeSureSendDataVerified && !state) makeSureSendDataVerified = false; + } + } + + /** + * Gets whether all sent fragments are verified to be equal. + * + * @return If all sent fragments will be verified to be equal. + */ + public boolean shouldSentDataBeAllVerified() { + return makeSureSendDataVerified; + } + + /** + * Gets whether all sent fragments are verified to be equal. + * Requires {@link #setResponseVerification(boolean)} set to true. + * + * @param state If all sent fragments will be verified to be equal. + */ + public void setSentDataWillBeAllVerified(boolean state) { + synchronized (slock) { + if (!verifyResponses) return; + makeSureSendDataVerified = state; } } @@ -276,6 +301,7 @@ public final class FragmentReceiver { * the {@link FragmentSendCompletePacket} or {@link FragmentRetrySendPacket} packets are sent. * A {@link FragmentSendCompletePacket} is sent if completely received and a * {@link FragmentRetrySendPacket} is sent if not completely received. + * This excludes empty packets due to {@link #shouldSentDataBeAllVerified()}. * * @return The number of send packet calls before a completion or restart is forced. */ @@ -288,6 +314,7 @@ public final class FragmentReceiver { * the {@link FragmentSendCompletePacket} or {@link FragmentRetrySendPacket} packets are sent. * A {@link FragmentSendCompletePacket} is sent if completely received and a * {@link FragmentRetrySendPacket} is sent if not completely received. + * This excludes empty packets due to {@link #shouldSentDataBeAllVerified()}. * * @param numberOfEmptySends The number of empty sends to allow. * @throws IllegalArgumentException numberOfEmptySends is less than 1. @@ -297,6 +324,28 @@ public final class FragmentReceiver { numberOfEmptySendsTillForced = numberOfEmptySends; } + /** + * Stops data verification for the specified Packet ID when {@link #shouldSentDataBeAllVerified()} is true. + * + * @param id The PacketID to act on. + */ + public void stopDataVerificationAndCompleteReceive(int id) { + synchronized (slock) { + if (!makeSureSendDataVerified) return; + FragmentInput input = registry.get(id); + if (input != null) input.verifyReceived = true; + } + } + + /** + * Stops data verification for all packets being received when {@link #shouldSentDataBeAllVerified()} is true. + */ + public void stopAllDataVerificationAndCompleteReceive() { + synchronized (slock) { + for (int c : registry.keySet()) registry.get(c).verifyReceived = true; + } + } + /** * This class provides the ability to store allocated responses to be sent back. * @@ -334,6 +383,7 @@ public final class FragmentReceiver { private int sendsTillCompleteForced; private boolean fsendActive = false; private final FragmentMessagePacket[] messagePackets; + public boolean verifyReceived = false; public FragmentInput(int id, int count, UUID aid) { packetID = id; @@ -355,12 +405,16 @@ public final class FragmentReceiver { if (fsendActive) { if (sendsTillCompleteForced > 0) sendsTillCompleteForced--; } else fsendActive = true; - if (sendsTillCompleteForced == 0) return (idsToReceive.size() < 1) ? new FragmentSendCompletePacket(packetID, true) : new FragmentRetrySendPacket(packetID, false); + if (sendsTillCompleteForced == 0 && !(makeSureSendDataVerified && !verifyReceived)) return (idsToReceive.size() < 1) ? new FragmentSendCompletePacket(packetID, true) : new FragmentRetrySendPacket(packetID, false); return null; } public void receivePacket(IPacket packetIn) { if ((packetIn instanceof FragmentSendCompletePacket && !((FragmentSendCompletePacket) packetIn).isAcknowledgement())) sendsTillCompleteForced = 0; + if (packetIn instanceof FragmentSendVerifyCompletePacket) { + sendsTillCompleteForced = 0; + verifyReceived = true; + } if ((packetIn instanceof FragmentRetrySendPacket && ((FragmentRetrySendPacket) packetIn).isAcknowledgement())) sendsTillCompleteForced = numberOfEmptySendsTillForced + 1; if (packetIn instanceof FragmentMessagePacket) { FragmentMessagePacket messagePacket = (FragmentMessagePacket) packetIn; @@ -371,7 +425,7 @@ public final class FragmentReceiver { } public IPacket consume() throws PacketException { - if (consumeDone || idsToReceive.size() > 0 || messagePackets.length < 1) return null; + if (consumeDone || idsToReceive.size() > 0 || messagePackets.length < 1 || (makeSureSendDataVerified && !verifyReceived)) return null; ByteArrayOutputStream packetStream = new ByteArrayOutputStream(messagePackets[0].getFragmentMessage().length); for (FragmentMessagePacket messagePacket : messagePackets) { try { diff --git a/src/com/captainalm/lib/calmnet/packet/FragmentSender.java b/src/com/captainalm/lib/calmnet/packet/FragmentSender.java index 9a29518..d529254 100644 --- a/src/com/captainalm/lib/calmnet/packet/FragmentSender.java +++ b/src/com/captainalm/lib/calmnet/packet/FragmentSender.java @@ -19,6 +19,7 @@ public final class FragmentSender { private int splitSize = 496; private PacketLoader packetLoader; private boolean verifyResponses = false; + private boolean makeSureSendDataVerified = false; /** * Constructs a new FragmentSender with the specified {@link PacketLoader}. @@ -241,12 +242,58 @@ public final class FragmentSender { /** * Sets whether responses should be verified. + * If set to false, {@link #setSentDataWillBeAllVerified(boolean)} will be set to false too. * * @param state If responses should be verified. */ public void setResponseVerification(boolean state) { synchronized (slock) { verifyResponses = state; + if (makeSureSendDataVerified && !state) makeSureSendDataVerified = false; + } + } + + /** + * Gets whether all sent fragments are verified to be equal. + * + * @return If all sent fragments will be verified to be equal. + */ + public boolean shouldSentDataBeAllVerified() { + return makeSureSendDataVerified; + } + + /** + * Gets whether all sent fragments are verified to be equal. + * Requires {@link #setResponseVerification(boolean)} set to true. + * + * @param state If all sent fragments will be verified to be equal. + */ + public void setSentDataWillBeAllVerified(boolean state) { + synchronized (slock) { + if (!verifyResponses) return; + makeSureSendDataVerified = state; + } + } + + /** + * Stops data verification for the specified Packet ID when {@link #shouldSentDataBeAllVerified()} is true. + * + * @param id The PacketID to act on. + */ + public void stopDataVerificationAndCompleteSend(int id) { + synchronized (slock) { + if (!makeSureSendDataVerified) return; + FragmentOutput output = registry.get(id); + if (output != null) output.forceDataVerifiedSendStop = true; + } + } + + /** + * Stops data verification for all packets being sent when {@link #shouldSentDataBeAllVerified()} is true. + */ + public void stopAllDataVerificationAndCompleteSend() { + synchronized (slock) { + for (int c : registry.keySet()) registry.get(c).forceDataVerifiedSendStop = true; } } @@ -263,6 +310,7 @@ public final class FragmentSender { private final ArrayList msgToResendCurrent = new ArrayList<>(); private int msgPacketIndex = 0; public boolean isResending = false; + public boolean forceDataVerifiedSendStop = false; public FragmentOutput(int id, byte[] toSplit) { packetID = id; @@ -282,12 +330,14 @@ public final class FragmentSender { msgPacketIndex = 0; return new FragmentRetrySendPacket(packetID, true); } + if (!isResending && makeSureSendDataVerified && msgPacketIndex >= messagePackets.length && !forceDataVerifiedSendStop) setResendingOn(true); if (isResending) { + if (makeSureSendDataVerified && msgPacketIndex >= msgToResendCurrent.size() && !forceDataVerifiedSendStop) setResendingOn(true); if (msgPacketIndex < msgToResendCurrent.size()) return messagePackets[msgToResendCurrent.get(msgPacketIndex++)]; } else { if (msgPacketIndex < messagePackets.length) return messagePackets[msgPacketIndex++]; } - return new FragmentSendCompletePacket(packetID, false); + return (makeSureSendDataVerified && (msgToResend.size() < 1 || forceDataVerifiedSendStop)) ? new FragmentSendVerifyCompletePacket(packetID) : new FragmentSendCompletePacket(packetID, false); } public boolean shouldBeRemovedReceivePacket(IPacket packetIn) { @@ -300,15 +350,17 @@ public final class FragmentSender { if (!verifyResponses || compareData(responsePacket.getFragmentMessage(), messagePackets[responsePacket.getFragmentID()].getFragmentMessage())) msgToResend.remove(responsePacket.getFragmentID()); } - if (packetIn instanceof FragmentRetrySendPacket && !((FragmentRetrySendPacket) packetIn).isAcknowledgement()) { - msgPacketIndex = -1; - isResending = true; - msgToResendCurrent.clear(); - msgToResendCurrent.addAll(msgToResend); - } + if (packetIn instanceof FragmentRetrySendPacket && !((FragmentRetrySendPacket) packetIn).isAcknowledgement()) setResendingOn(false); return false; } + private void setResendingOn(boolean zeroIndex) { + msgPacketIndex = (zeroIndex) ? 0 : -1; + isResending = true; + msgToResendCurrent.clear(); + msgToResendCurrent.addAll(msgToResend); + } + private boolean compareData(byte[] data1, byte[] data2) { if ((data1 == null && data2 != null) || (data1 != null && data2 == null)) return false; if (data1 == data2) return true;