public void testAckOnlyCreation() throws BlockedTooLongException, InterruptedException { NewPacketFormat npf = new NewPacketFormat(null, 0, 0, NEW_FORMAT); PeerMessageQueue pmq = new PeerMessageQueue(); SessionKey s = new SessionKey( null, null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0)); NPFPacket p = null; // Packet that should be acked p = new NPFPacket(); p.addMessageFragment( new MessageFragment( true, false, true, 0, 8, 8, 0, new byte[] { (byte) 0x01, (byte) 0x23, (byte) 0x45, (byte) 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }, null)); assertEquals(1, npf.handleDecryptedPacket(p, s).size()); Thread.sleep(NewPacketFormatKeyContext.MAX_ACK_DELAY * 2); p = npf.createPacket(1400, pmq, s, false); assertEquals(1, p.getAcks().size()); }
public void testOutOfOrderDelivery() throws BlockedTooLongException { NewPacketFormat sender = new NewPacketFormat(null, 0, 0, NEW_FORMAT); PeerMessageQueue senderQueue = new PeerMessageQueue(); NewPacketFormat receiver = new NewPacketFormat(null, 0, 0, NEW_FORMAT); SessionKey senderKey = new SessionKey( null, null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0)); SessionKey receiverKey = new SessionKey( null, null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0)); senderQueue.queueAndEstimateSize(new MessageItem(new byte[1024], null, false, null, (short) 0)); NPFPacket fragment1 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment1.getFragments().size()); NPFPacket fragment2 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment2.getFragments().size()); NPFPacket fragment3 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment3.getFragments().size()); receiver.handleDecryptedPacket(fragment1, receiverKey); receiver.handleDecryptedPacket(fragment3, receiverKey); assertEquals(1, receiver.handleDecryptedPacket(fragment2, receiverKey).size()); }
public static NPFPacket create(byte[] plaintext, BasePeerNode pn) { NPFPacket packet = new NPFPacket(); if (pn == null) throw new IllegalArgumentException("Can't estimate an ack type of received packet"); int offset = 0; if (plaintext.length < (offset + 5)) { // Sequence number + the number of acks packet.error = true; return packet; } packet.sequenceNumber = ((plaintext[offset] & 0xFF) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; // Process received acks int numAckRanges = plaintext[offset++] & 0xFF; if (numAckRanges > 0) { try { int ack, prevAck = 0; for (int i = 0; i < numAckRanges; i++) { if (i == 0) { ack = ((plaintext[offset] & 0xFF) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; } else { int distanceFromPrevious = (plaintext[offset++] & 0xFF); if (distanceFromPrevious != 0) { ack = prevAck + distanceFromPrevious; } else { // Far offset ack = ((plaintext[offset] & 0xFF) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; } } int rangeSize = (plaintext[offset++] & 0xFF); for (int j = 1; j <= rangeSize; j++) { packet.acks.add(ack++); } prevAck = ack - 1; } } catch (ArrayIndexOutOfBoundsException e) { // The packet's length is not big enough packet.error = true; return packet; } } // Handle received message fragments int prevFragmentID = -1; while (offset < plaintext.length) { boolean shortMessage = (plaintext[offset] & 0x80) != 0; boolean isFragmented = (plaintext[offset] & 0x40) != 0; boolean firstFragment = (plaintext[offset] & 0x20) != 0; if (!isFragmented && !firstFragment) { // Padding or lossy messages. offset = tryParseLossyMessages(packet, plaintext, offset); break; } int messageID = -1; if ((plaintext[offset] & 0x10) != 0) { if (plaintext.length < (offset + 4)) { packet.error = true; return packet; } messageID = ((plaintext[offset] & 0x0F) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; } else { if (plaintext.length < (offset + 2)) { packet.error = true; return packet; } if (prevFragmentID == -1) { Logger.warning(NPFPacket.class, "First fragment doesn't have full message id"); packet.error = true; return packet; } messageID = prevFragmentID + (((plaintext[offset] & 0x0F) << 8) | (plaintext[offset + 1] & 0xFF)); offset += 2; } prevFragmentID = messageID; int requiredLength = offset + (shortMessage ? 1 : 2) + (isFragmented ? (shortMessage ? 1 : 3) : 0); if (plaintext.length < requiredLength) { packet.error = true; return packet; } int fragmentLength; if (shortMessage) { fragmentLength = plaintext[offset++] & 0xFF; } else { fragmentLength = ((plaintext[offset] & 0xFF) << 8) | (plaintext[offset + 1] & 0xFF); offset += 2; } int messageLength = -1; int fragmentOffset = 0; if (isFragmented) { int value; if (shortMessage) { value = plaintext[offset++] & 0xFF; } else { value = ((plaintext[offset] & 0xFF) << 8) | (plaintext[offset + 1] & 0xFF); offset += 2; } if (firstFragment) { messageLength = value; if (messageLength == fragmentLength) { Logger.warning( NPFPacket.class, "Received fragmented message, but fragment contains the entire message"); } } else { fragmentOffset = value; } } else { messageLength = fragmentLength; } if ((offset + fragmentLength) > plaintext.length) { Logger.error( NPFPacket.class, "Fragment doesn't fit in the received packet: offset is " + offset + " fragment length is " + fragmentLength + " plaintext length is " + plaintext.length + " message length " + messageLength + " message ID " + messageID + (pn == null ? "" : (" from " + pn.shortToString()))); packet.error = true; break; } byte[] fragmentData = Arrays.copyOfRange(plaintext, offset, offset + fragmentLength); offset += fragmentLength; packet.fragments.add( new MessageFragment( shortMessage, isFragmented, firstFragment, messageID, fragmentLength, messageLength, fragmentOffset, fragmentData, null)); } packet.length = offset; return packet; }
public static NPFPacket create(byte[] plaintext, BasePeerNode pn) { NPFPacket packet = new NPFPacket(); int offset = 0; if (plaintext.length < (offset + 5)) { // Sequence number + the number of acks packet.error = true; return packet; } packet.sequenceNumber = ((plaintext[offset] & 0xFF) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; // Process received acks int numAcks = plaintext[offset++] & 0xFF; if (plaintext.length < (offset + numAcks + (numAcks > 0 ? 3 : 0))) { packet.error = true; return packet; } int prevAck = 0; for (int i = 0; i < numAcks; i++) { int ack = 0; if (i == 0) { ack = ((plaintext[offset] & 0xFF) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; } else { ack = prevAck + (plaintext[offset++] & 0xFF); } packet.acks.add(ack); prevAck = ack; } // Handle received message fragments int prevFragmentID = -1; while (offset < plaintext.length) { boolean shortMessage = (plaintext[offset] & 0x80) != 0; boolean isFragmented = (plaintext[offset] & 0x40) != 0; boolean firstFragment = (plaintext[offset] & 0x20) != 0; if (!isFragmented && !firstFragment) { // Padding or lossy messages. offset = tryParseLossyMessages(packet, plaintext, offset); break; } int messageID = -1; if ((plaintext[offset] & 0x10) != 0) { if (plaintext.length < (offset + 4)) { packet.error = true; return packet; } messageID = ((plaintext[offset] & 0x0F) << 24) | ((plaintext[offset + 1] & 0xFF) << 16) | ((plaintext[offset + 2] & 0xFF) << 8) | (plaintext[offset + 3] & 0xFF); offset += 4; } else { if (plaintext.length < (offset + 2)) { packet.error = true; return packet; } if (prevFragmentID == -1) { Logger.warning(NPFPacket.class, "First fragment doesn't have full message id"); packet.error = true; return packet; } messageID = prevFragmentID + (((plaintext[offset] & 0x0F) << 8) | (plaintext[offset + 1] & 0xFF)); offset += 2; } prevFragmentID = messageID; int requiredLength = offset + (shortMessage ? 1 : 2) + (isFragmented ? (shortMessage ? 1 : 3) : 0); if (plaintext.length < requiredLength) { packet.error = true; return packet; } int fragmentLength; if (shortMessage) { fragmentLength = plaintext[offset++] & 0xFF; } else { fragmentLength = ((plaintext[offset] & 0xFF) << 8) | (plaintext[offset + 1] & 0xFF); offset += 2; } int messageLength = -1; int fragmentOffset = 0; if (isFragmented) { int value; if (shortMessage) { value = plaintext[offset++] & 0xFF; } else { value = ((plaintext[offset] & 0xFF) << 8) | (plaintext[offset + 1] & 0xFF); offset += 2; } if (firstFragment) { messageLength = value; if (messageLength == fragmentLength) { Logger.warning( NPFPacket.class, "Received fragmented message, but fragment contains the entire message"); } } else { fragmentOffset = value; } } else { messageLength = fragmentLength; } byte[] fragmentData = new byte[fragmentLength]; if ((offset + fragmentLength) > plaintext.length) { Logger.error( NPFPacket.class, "Fragment doesn't fit in the received packet: offset is " + offset + " fragment length is " + fragmentLength + " plaintext length is " + plaintext.length + " message length " + messageLength + " message ID " + messageID + (pn == null ? "" : (" from " + pn.shortToString()))); packet.error = true; break; } System.arraycopy(plaintext, offset, fragmentData, 0, fragmentLength); offset += fragmentLength; packet.fragments.add( new MessageFragment( shortMessage, isFragmented, firstFragment, messageID, fragmentLength, messageLength, fragmentOffset, fragmentData, null)); } packet.length = offset; return packet; }
public void testLostLastAck() throws BlockedTooLongException, InterruptedException { NullBasePeerNode senderNode = new NullBasePeerNode(); NewPacketFormat sender = new NewPacketFormat(senderNode, 0, 0, NEW_FORMAT); PeerMessageQueue senderQueue = new PeerMessageQueue(); NewPacketFormat receiver = new NewPacketFormat(null, 0, 0, NEW_FORMAT); PeerMessageQueue receiverQueue = new PeerMessageQueue(); SessionKey senderKey = new SessionKey( null, null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0)); senderNode.currentKey = senderKey; SessionKey receiverKey = new SessionKey( null, null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0)); senderQueue.queueAndEstimateSize(new MessageItem(new byte[1024], null, false, null, (short) 0)); NPFPacket fragment1 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment1.getFragments().size()); receiver.handleDecryptedPacket(fragment1, receiverKey); NPFPacket fragment2 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment2.getFragments().size()); receiver.handleDecryptedPacket(fragment2, receiverKey); Thread.sleep(NewPacketFormatKeyContext.MAX_ACK_DELAY * 2); NPFPacket ack1 = receiver.createPacket(512, receiverQueue, receiverKey, false); assertEquals(2, ack1.getAcks().size()); assertEquals(0, (int) ack1.getAcks().first()); assertEquals(1, (int) ack1.getAcks().last()); sender.handleDecryptedPacket(ack1, senderKey); NPFPacket fragment3 = sender.createPacket(512, senderQueue, senderKey, false); assertEquals(1, fragment3.getFragments().size()); receiver.handleDecryptedPacket(fragment3, receiverKey); Thread.sleep(NewPacketFormatKeyContext.MAX_ACK_DELAY * 2); receiver.createPacket(512, senderQueue, receiverKey, false); // Sent, but lost try { Thread.sleep(1000); // RTT is 250ms by default since there is no PeerNode to track it } catch (InterruptedException e) { fail(); } NPFPacket resend1 = sender.createPacket(512, senderQueue, senderKey, false); if (resend1 == null) fail("No packet to resend"); assertEquals(0, receiver.handleDecryptedPacket(resend1, receiverKey).size()); // Make sure an ack is sent Thread.sleep(NewPacketFormatKeyContext.MAX_ACK_DELAY * 2); NPFPacket ack2 = receiver.createPacket(512, receiverQueue, receiverKey, false); assertNotNull(ack2); assertEquals(1, ack2.getAcks().size()); assertEquals(0, ack2.getFragments().size()); }