Finish implementing fragment verification.

This commit is contained in:
Captain ALM 2022-06-14 16:35:14 +01:00
parent 96c9864092
commit fcd985b570
Signed by: alfred
GPG Key ID: 4E4ADD02609997B1
3 changed files with 121 additions and 9 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -25,6 +25,7 @@ public final class FragmentReceiver {
private PacketLoader packetLoader; private PacketLoader packetLoader;
private IPacketFactory packetFactory; private IPacketFactory packetFactory;
private boolean verifyResponses = false; private boolean verifyResponses = false;
private boolean makeSureSendDataVerified = false;
/** /**
* Constructs a new FragmentReceiver with the specified {@link PacketLoader} and {@link IPacketFactory}. * 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. * 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. * @param state If responses should be verified.
*/ */
public void setResponseVerification(boolean state) { public void setResponseVerification(boolean state) {
synchronized (slock) { synchronized (slock) {
verifyResponses = state; 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. * the {@link FragmentSendCompletePacket} or {@link FragmentRetrySendPacket} packets are sent.
* A {@link FragmentSendCompletePacket} is sent if completely received and a * A {@link FragmentSendCompletePacket} is sent if completely received and a
* {@link FragmentRetrySendPacket} is sent if not completely received. * {@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. * @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. * the {@link FragmentSendCompletePacket} or {@link FragmentRetrySendPacket} packets are sent.
* A {@link FragmentSendCompletePacket} is sent if completely received and a * A {@link FragmentSendCompletePacket} is sent if completely received and a
* {@link FragmentRetrySendPacket} is sent if not completely received. * {@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. * @param numberOfEmptySends The number of empty sends to allow.
* @throws IllegalArgumentException numberOfEmptySends is less than 1. * @throws IllegalArgumentException numberOfEmptySends is less than 1.
@ -297,6 +324,28 @@ public final class FragmentReceiver {
numberOfEmptySendsTillForced = numberOfEmptySends; 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. * 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 int sendsTillCompleteForced;
private boolean fsendActive = false; private boolean fsendActive = false;
private final FragmentMessagePacket[] messagePackets; private final FragmentMessagePacket[] messagePackets;
public boolean verifyReceived = false;
public FragmentInput(int id, int count, UUID aid) { public FragmentInput(int id, int count, UUID aid) {
packetID = id; packetID = id;
@ -355,12 +405,16 @@ public final class FragmentReceiver {
if (fsendActive) { if (fsendActive) {
if (sendsTillCompleteForced > 0) sendsTillCompleteForced--; if (sendsTillCompleteForced > 0) sendsTillCompleteForced--;
} else fsendActive = true; } 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; return null;
} }
public void receivePacket(IPacket packetIn) { public void receivePacket(IPacket packetIn) {
if ((packetIn instanceof FragmentSendCompletePacket && !((FragmentSendCompletePacket) packetIn).isAcknowledgement())) sendsTillCompleteForced = 0; 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 FragmentRetrySendPacket && ((FragmentRetrySendPacket) packetIn).isAcknowledgement())) sendsTillCompleteForced = numberOfEmptySendsTillForced + 1;
if (packetIn instanceof FragmentMessagePacket) { if (packetIn instanceof FragmentMessagePacket) {
FragmentMessagePacket messagePacket = (FragmentMessagePacket) packetIn; FragmentMessagePacket messagePacket = (FragmentMessagePacket) packetIn;
@ -371,7 +425,7 @@ public final class FragmentReceiver {
} }
public IPacket consume() throws PacketException { 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); ByteArrayOutputStream packetStream = new ByteArrayOutputStream(messagePackets[0].getFragmentMessage().length);
for (FragmentMessagePacket messagePacket : messagePackets) { for (FragmentMessagePacket messagePacket : messagePackets) {
try { try {

View File

@ -19,6 +19,7 @@ public final class FragmentSender {
private int splitSize = 496; private int splitSize = 496;
private PacketLoader packetLoader; private PacketLoader packetLoader;
private boolean verifyResponses = false; private boolean verifyResponses = false;
private boolean makeSureSendDataVerified = false;
/** /**
* Constructs a new FragmentSender with the specified {@link PacketLoader}. * Constructs a new FragmentSender with the specified {@link PacketLoader}.
@ -241,12 +242,58 @@ public final class FragmentSender {
/** /**
* Sets whether responses should be verified. * 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. * @param state If responses should be verified.
*/ */
public void setResponseVerification(boolean state) { public void setResponseVerification(boolean state) {
synchronized (slock) { synchronized (slock) {
verifyResponses = state; 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<Integer> msgToResendCurrent = new ArrayList<>(); private final ArrayList<Integer> msgToResendCurrent = new ArrayList<>();
private int msgPacketIndex = 0; private int msgPacketIndex = 0;
public boolean isResending = false; public boolean isResending = false;
public boolean forceDataVerifiedSendStop = false;
public FragmentOutput(int id, byte[] toSplit) { public FragmentOutput(int id, byte[] toSplit) {
packetID = id; packetID = id;
@ -282,12 +330,14 @@ public final class FragmentSender {
msgPacketIndex = 0; msgPacketIndex = 0;
return new FragmentRetrySendPacket(packetID, true); return new FragmentRetrySendPacket(packetID, true);
} }
if (!isResending && makeSureSendDataVerified && msgPacketIndex >= messagePackets.length && !forceDataVerifiedSendStop) setResendingOn(true);
if (isResending) { if (isResending) {
if (makeSureSendDataVerified && msgPacketIndex >= msgToResendCurrent.size() && !forceDataVerifiedSendStop) setResendingOn(true);
if (msgPacketIndex < msgToResendCurrent.size()) return messagePackets[msgToResendCurrent.get(msgPacketIndex++)]; if (msgPacketIndex < msgToResendCurrent.size()) return messagePackets[msgToResendCurrent.get(msgPacketIndex++)];
} else { } else {
if (msgPacketIndex < messagePackets.length) return messagePackets[msgPacketIndex++]; 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) { public boolean shouldBeRemovedReceivePacket(IPacket packetIn) {
@ -300,14 +350,16 @@ public final class FragmentSender {
if (!verifyResponses || compareData(responsePacket.getFragmentMessage(), messagePackets[responsePacket.getFragmentID()].getFragmentMessage())) if (!verifyResponses || compareData(responsePacket.getFragmentMessage(), messagePackets[responsePacket.getFragmentID()].getFragmentMessage()))
msgToResend.remove(responsePacket.getFragmentID()); msgToResend.remove(responsePacket.getFragmentID());
} }
if (packetIn instanceof FragmentRetrySendPacket && !((FragmentRetrySendPacket) packetIn).isAcknowledgement()) { if (packetIn instanceof FragmentRetrySendPacket && !((FragmentRetrySendPacket) packetIn).isAcknowledgement()) setResendingOn(false);
msgPacketIndex = -1; return false;
}
private void setResendingOn(boolean zeroIndex) {
msgPacketIndex = (zeroIndex) ? 0 : -1;
isResending = true; isResending = true;
msgToResendCurrent.clear(); msgToResendCurrent.clear();
msgToResendCurrent.addAll(msgToResend); msgToResendCurrent.addAll(msgToResend);
} }
return false;
}
private boolean compareData(byte[] data1, byte[] data2) { private boolean compareData(byte[] data1, byte[] data2) {
if ((data1 == null && data2 != null) || (data1 != null && data2 == null)) return false; if ((data1 == null && data2 != null) || (data1 != null && data2 == null)) return false;