From bc9a28e52dbfe0831aea3fca8e09db382b9d542c Mon Sep 17 00:00:00 2001 From: thsc42 Date: Wed, 6 Jan 2021 19:22:57 +0100 Subject: [PATCH] what a fatal and embarrassing bug in ASAPSerialization could be fixed now. Now we can exchange messages with a length greater than 255. --- .../asap/protocol/AssimilationPDU_Impl.java | 5 +- .../sharksystem/utils/ASAPSerialization.java | 86 ++++++++- test/net/sharksystem/asap/LongerMessages.java | 177 ++++++++++++++++++ .../sharksystem/asap/Point2PointTests.java | 4 +- test/net/sharksystem/asap/V1TestSuite.java | 3 +- 5 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 test/net/sharksystem/asap/LongerMessages.java diff --git a/src/net/sharksystem/asap/protocol/AssimilationPDU_Impl.java b/src/net/sharksystem/asap/protocol/AssimilationPDU_Impl.java index 2876845..980844a 100644 --- a/src/net/sharksystem/asap/protocol/AssimilationPDU_Impl.java +++ b/src/net/sharksystem/asap/protocol/AssimilationPDU_Impl.java @@ -77,8 +77,7 @@ static void sendPDUWithoutCmd(CharSequence peer, CharSequence recipient, CharSeq ASAPSerialization.writeCharSequenceParameter(channel, os); // opt ASAPSerialization.writeNonNegativeIntegerParameter(era, os); // opt ASAPSerialization.writeCharSequenceParameter(list2string(offsets), os); // opt - - ASAPSerialization.writeNonNegativeLongParameter(length, os); // mand + ASAPSerialization.writeLongParameter(length, os); // mand // stream data while(length-- > 0) { @@ -135,7 +134,7 @@ public List getMessageOffsets() { @Override public byte[] getData() throws IOException { - if(data == null) { + if(this.data == null) { if(this.dataNoLongerOnStream) throw new IOException(this.getLogStart() + "data are already read from stream, probably with streamData"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/src/net/sharksystem/utils/ASAPSerialization.java b/src/net/sharksystem/utils/ASAPSerialization.java index 094e15c..2a52680 100644 --- a/src/net/sharksystem/utils/ASAPSerialization.java +++ b/src/net/sharksystem/utils/ASAPSerialization.java @@ -10,6 +10,13 @@ import java.util.Set; public class ASAPSerialization { + public static final long BLANK_LEFT_LONG = 0x00000000FFFFFFFFL; + public static final long BLANK_RIGHT_LONG = 0xFFFFFFFF00000000L; + public static final int BLANK_LEFT_INTEGER = 0x0000FFFF; + public static final int BLANK_RIGHT_INTEGER = 0xFFFF0000; + public static final short BLANK_LEFT_SHORT = 0x00FF; + public static final short BLANK_RIGHT_SHORT = (short) 0xFF00; + public static void writeByteArray(byte[] bytes2Write, OutputStream os) throws IOException { writeNonNegativeIntegerParameter(bytes2Write.length, os); os.write(bytes2Write); @@ -37,12 +44,14 @@ public static void writeByteParameter(byte parameter, OutputStream os) throws IO os.write(new byte[] { parameter} ); } - public static void writeShortParameter(short parameter, OutputStream os) throws IOException { + public static void writeShortParameter(short shortValue, OutputStream os) throws IOException { // short = 16 bit = 2 bytes - int leftInt = parameter >> 8; - writeByteParameter( (byte)leftInt, os); + short left = (short) (shortValue & BLANK_RIGHT_SHORT); + left = (short) (left >> 8); + short right = (short) (shortValue & BLANK_LEFT_SHORT); + writeByteParameter( (byte)left, os); // cut left part - writeByteParameter( (byte)parameter, os); + writeByteParameter( (byte)right, os); } public static void writeNonNegativeIntegerParameter(int parameter, OutputStream os) throws IOException { @@ -54,13 +63,53 @@ public static void writeNonNegativeIntegerParameter(int parameter, OutputStream writeShortParameter((short) parameter, os); } + public static void writeIntegerParameter(int intValue, OutputStream os) throws IOException { + // Integer == 32 bit == 4 Byte + int left = intValue & BLANK_RIGHT_INTEGER; + left = left >> 16; + int right = intValue & BLANK_LEFT_INTEGER; + writeShortParameter((short) left, os); + writeShortParameter((short) right, os); + } + public static void writeNonNegativeLongParameter(long longValue, OutputStream os) throws IOException { - if(longValue < 0) return; + if(longValue > -1) writeLongParameter(longValue, os); + } + public static void writeLongParameter(long longValue, OutputStream os) throws IOException { // Long = 64 bit = 2 Integer - long left = longValue >> 32; - writeNonNegativeIntegerParameter((int) left, os); - writeNonNegativeIntegerParameter((int) longValue, os); + long left = longValue & BLANK_RIGHT_LONG; + left = left >> 32; + long right = longValue & BLANK_LEFT_LONG; + writeIntegerParameter((int)left, os); + writeIntegerParameter((int)right, os); + } + + public static void printBits(long l, int bits) { + long mask = 1; + mask = mask << bits-1; + short byteBitCounter = 4; + while(mask != 0) { + if((l & mask) != 0) System.out.print("1"); + else System.out.print("0"); + if(--byteBitCounter == 0) { + byteBitCounter = 4; + System.out.print(" "); + } + mask = mask >> 1; + } + System.out.print(" "); + } + + public static void printByte(short s) { printBits(s, 8); } + public static void printBits(short s) { printBits(s, 16); } + public static void printBits(int i) { printBits(i, 32); } + public static void printBits(long l) { + long left = l & BLANK_RIGHT_LONG; + left = left >> 32; + printBits((int) left); + long right = l & BLANK_LEFT_LONG; + printBits((int) right); } public static byte readByteParameter(InputStream is) throws IOException, ASAPException { @@ -78,24 +127,45 @@ public static byte readByte(InputStream is) throws IOException, ASAPException { public static short readShortParameter(InputStream is) throws IOException, ASAPException { int value = readByteParameter(is); value = value << 8; + // by sure + value = value & BLANK_RIGHT_SHORT; int right = readByteParameter(is); + // by sure + right = right & BLANK_LEFT_SHORT; value += right; + return (short) value; } public static int readIntegerParameter(InputStream is) throws IOException, ASAPException { int value = readShortParameter(is); value = value << 16; + value = value & BLANK_RIGHT_INTEGER; + int right = readShortParameter(is); + right = right & BLANK_LEFT_INTEGER; + value += right; + return value; } public static long readLongParameter(InputStream is) throws IOException, ASAPException { long value = readIntegerParameter(is); value = value << 32; + value = value & BLANK_RIGHT_LONG; + long right = readIntegerParameter(is); + right = right & BLANK_LEFT_LONG; + value += right; + + /* + System.out.println("readLongParameter"); + printBits(value); + System.out.print("\n"); + */ + return value; } diff --git a/test/net/sharksystem/asap/LongerMessages.java b/test/net/sharksystem/asap/LongerMessages.java new file mode 100644 index 0000000..1cdbce8 --- /dev/null +++ b/test/net/sharksystem/asap/LongerMessages.java @@ -0,0 +1,177 @@ +package net.sharksystem.asap; + +import net.sharksystem.asap.util.ASAPChunkReceivedTester; +import net.sharksystem.asap.util.ASAPPeerHandleConnectionThread; +import net.sharksystem.cmdline.TCPStream; +import net.sharksystem.utils.ASAPSerialization; +import org.junit.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Iterator; + +import static net.sharksystem.asap.ASAPPeer.DEFAULT_MAX_PROCESSING_TIME; + +public class LongerMessages { + public static final String ALICE_BOB_CHAT_URL = "content://aliceAndBob.talk"; + public static final String CHAT_FORMAT = "application/x-sn2-makan"; + public static final String ALICE_ROOT_FOLDER = "longmessage/Alice"; + public static final String ALICE_APP_FOLDER = ALICE_ROOT_FOLDER + "/appFolder"; + public static final String BOB_ROOT_FOLDER = "longmessage/Bob"; + public static final String BOB_APP_FOLDER = BOB_ROOT_FOLDER + "/appFolder"; + public static final String ALICE = "Alice"; + public static final String BOB = "Bob"; + // 200 + public static final String ALICE2BOB_MESSAGE = "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; + //public static final String ALICE2BOB_MESSAGE = "Hi Bob"; + //public static final String ALICE2BOB_MESSAGE2 = "HiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgain"; + public static final String ALICE2BOB_MESSAGE2 = "Hi Again"; + + private static int portnumber = 7777; + + private int getPortNumber() { + portnumber++; + return portnumber; + } + + @Test + public void serializeDeserializeTest() throws IOException, ASAPException { + long writeLong = 0x9ABCDEF012345678L; + //long writeLong = 0x9999999999999999L; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ASAPSerialization.writeLongParameter(writeLong, baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + long readLong = ASAPSerialization.readLongParameter(bais); + + Assert.assertEquals(writeLong, readLong); + } + + @Test + public void longerMessagesAlice2Bob() throws IOException, ASAPException, InterruptedException { + /////////////////////////////////////////////////////////////////////////////////////////////////// + // prepare storages // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + ASAPEngineFS.removeFolder(ALICE_ROOT_FOLDER); // clean previous version before + ASAPEngineFS.removeFolder(BOB_ROOT_FOLDER); // clean previous version before + + // alice writes a message into chunkStorage + ASAPStorage aliceStorage = ASAPEngineFS.getASAPStorage(ALICE, ALICE_APP_FOLDER, CHAT_FORMAT); + + int aliceInitialEra = aliceStorage.getEra(); + + aliceStorage.createChannel(ALICE_BOB_CHAT_URL, BOB); + + // content changed - next change in topology should increase alice era. + aliceStorage.add(ALICE_BOB_CHAT_URL, ALICE2BOB_MESSAGE); + + // bob does the same + ASAPStorage bobStorage = ASAPEngineFS.getASAPStorage(BOB, BOB_APP_FOLDER, CHAT_FORMAT); + + int bobInitialEra = bobStorage.getEra(); + + bobStorage.createChannel(ALICE_BOB_CHAT_URL, ALICE); + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // prepare multi engines // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + ASAPChunkReceivedTester aliceListener = new ASAPChunkReceivedTester(); + ASAPPeer aliceEngine = ASAPPeerFS.createASAPPeer( + ALICE, ALICE_ROOT_FOLDER, DEFAULT_MAX_PROCESSING_TIME, aliceListener); + + ASAPChunkReceivedTester bobListener = new ASAPChunkReceivedTester(); + ASAPPeer bobEngine = ASAPPeerFS.createASAPPeer( + BOB, BOB_ROOT_FOLDER, DEFAULT_MAX_PROCESSING_TIME, bobListener); + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // prepare asap immediate bypass // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + ASAPAbstractOnlineMessageSender aliceBypass = new ASAPSingleProcessOnlineMessageSender(aliceEngine, aliceStorage); + ASAPAbstractOnlineMessageSender bobBypass = new ASAPSingleProcessOnlineMessageSender(bobEngine, bobStorage); + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // setup connection // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + int portNumber = this.getPortNumber(); + // create connections for both sides + TCPStream aliceChannel = new TCPStream(portNumber, true, "a2b"); + TCPStream bobChannel = new TCPStream(portNumber, false, "b2a"); + + aliceChannel.start(); + bobChannel.start(); + + // wait to connect + aliceChannel.waitForConnection(); + bobChannel.waitForConnection(); + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // run asap connection // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + // run engine as thread + ASAPPeerHandleConnectionThread aliceEngineThread = new ASAPPeerHandleConnectionThread(aliceEngine, + aliceChannel.getInputStream(), aliceChannel.getOutputStream()); + + aliceEngineThread.start(); + + // and better debugging - no new thread + bobEngine.handleConnection(bobChannel.getInputStream(), bobChannel.getOutputStream()); + + // give handleConnection some time. + Thread.sleep(1000); + // create second message after creating a connection - should be bypassed. + //aliceStorage.add(ALICE_BOB_CHAT_URL, ALICE2BOB_MESSAGE2); + + // wait until communication probably ends + System.out.flush(); + System.err.flush(); + Thread.sleep(2000); + System.out.flush(); + System.err.flush(); + + // close connections: note ASAPEngine does NOT close any connection!! + aliceChannel.close(); + bobChannel.close(); + System.out.flush(); + System.err.flush(); + Thread.sleep(1000); + System.out.flush(); + System.err.flush(); + + // check results + + // listener must have been informed about new messages + Assert.assertTrue(bobListener.chunkReceived()); + + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // open incoming storages // + /////////////////////////////////////////////////////////////////////////////////////////////////// + + // get message bob received + ASAPChunkStorage bobIncomingAliceStorage = bobStorage.getReceivedChunksStorage(ALICE); + ASAPChunk bobReceivedChunk = bobIncomingAliceStorage.getChunk(ALICE_BOB_CHAT_URL, aliceInitialEra); + + // #1 + Iterator bobReceivedMessages = bobReceivedChunk.getMessagesAsCharSequence(); + CharSequence bobReceivedMessage = bobReceivedMessages.next(); + Assert.assertEquals(ALICE2BOB_MESSAGE, bobReceivedMessage); + + // #2 - in next era + /* + bobReceivedChunk = bobIncomingAliceStorage.getChunk(ALICE_BOB_CHAT_URL, ASAP.nextEra(aliceInitialEra)); + bobReceivedMessages = bobReceivedChunk.getMessagesAsCharSequence(); + bobReceivedMessage = bobReceivedMessages.next(); + Assert.assertEquals(ALICE2BOB_MESSAGE2, bobReceivedMessage); + + */ + + Thread.sleep(1000); + } + +} diff --git a/test/net/sharksystem/asap/Point2PointTests.java b/test/net/sharksystem/asap/Point2PointTests.java index 304c9d7..716726e 100644 --- a/test/net/sharksystem/asap/Point2PointTests.java +++ b/test/net/sharksystem/asap/Point2PointTests.java @@ -26,7 +26,9 @@ public class Point2PointTests { public static final String ALICE = "Alice"; public static final String BOB = "Bob"; public static final String ALICE2BOB_MESSAGE = "Hi Bob"; - public static final String ALICE2BOB_MESSAGE2 = "Hi Bob again"; + // 400 characters + //public static final String ALICE2BOB_MESSAGE2 = "HiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgainHiYouAgain"; + public static final String ALICE2BOB_MESSAGE2 = "Hi You Again"; public static final String BOB2ALICE_MESSAGE = "Hi Alice"; public static final String BOB2ALICE_MESSAGE2 = "Hi Alice again"; diff --git a/test/net/sharksystem/asap/V1TestSuite.java b/test/net/sharksystem/asap/V1TestSuite.java index 4e965e2..131b494 100644 --- a/test/net/sharksystem/asap/V1TestSuite.java +++ b/test/net/sharksystem/asap/V1TestSuite.java @@ -15,7 +15,8 @@ CreateNewChannelFromOutsideTest.class, PDUTests.class, CryptoTests.class, - SNMessageASAPSerializationTests.class + SNMessageASAPSerializationTests.class, + LongerMessages.class }) public class V1TestSuite {