public void testEncodeDecodeLossyPerPacketMessages() { NPFPacket p = new NPFPacket(); byte[] fragData = new byte[] {(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF}; p.addMessageFragment(new MessageFragment(true, false, true, 0, 8, 8, 0, fragData, null)); byte[] lossyFragment = new byte[] { (byte)0xFF, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBB, (byte)0xAA}; p.addLossyMessage(lossyFragment); byte[] encoded = new byte[p.getLength()]; p.toBytes(encoded, 0, null); NPFPacket received = NPFPacket.create(encoded, pn); assertEquals(1, received.getFragments().size()); assertEquals(0, received.countAcks()); assertEquals(1, received.getLossyMessages().size()); assertEquals(encoded.length, received.getLength()); byte[] decodedFragData = received.getFragments().get(0).fragmentData; checkEquals(fragData, decodedFragData); byte[] decodedLossyMessage = received.getLossyMessages().get(0); checkEquals(lossyFragment, decodedLossyMessage); }
public void testSendPacketWithAckRange() { NPFPacket p = new NPFPacket(); p.setSequenceNumber(0); p.addAck(0, MAX_PACKET_SIZE); p.addAck(1, MAX_PACKET_SIZE); p.addAck(2, MAX_PACKET_SIZE); byte[] correctData = new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x03}; checkPacket(p, correctData); }
public void testEmptyPacket() { byte[] packet = new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, //Sequence number 0 (byte)0x00}; // 0 acks NPFPacket r = NPFPacket.create(packet, pn); assertEquals(0, r.getSequenceNumber()); assertEquals(0, r.getAcks().size()); assertEquals(0, r.getFragments().size()); assertFalse(r.getError()); }
public void testSendEmptyPacket() { NPFPacket p = new NPFPacket(); p.setSequenceNumber(0); byte[] correctData = new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, //Sequence number (0) (byte)0x00}; //Number of acks (0) checkPacket(p, correctData); }
NPFPacket packet = new NPFPacket(); SentPacket sentPacket = new SentPacket(this, sessionKey); int numAcks = packet.countAcks(); while(it.hasNext() && packet.getLength() < maxPacketSize) { MessageWrapper wrapper = it.next(); while(packet.getLength() < maxPacketSize) { MessageFragment frag = wrapper.getMessageFragment(maxPacketSize - packet.getLength()); if(frag == null) break; mustSend = true; addedFragments = true; packet.addMessageFragment(frag); sentPacket.addFragment(frag); if(wrapper.allSent()) { packet.addLossyMessage(buf, maxPacketSize); packet.addLossyMessage(buf, maxPacketSize); if((!mustSend) && packet.getLength() >= (maxPacketSize * 4 / 5)) { if(logDEBUG) Logger.debug(this, "Must send because packet is big on acks alone"); if(messageQueue.mustSendNow(now) || messageQueue.mustSendSize(packet.getLength(), maxPacketSize)) { if(logDEBUG) Logger.debug(this, "Must send because of message queue"); mustSend = true; packet.getFragments().isEmpty()) mustSendKeepalive = true;
if(packet == null) return false; int paddedLen = packet.getLength() + HMAC_LENGTH; if(pn.shouldPadDataPackets()) { int packetLength = paddedLen; packet.toBytes(data, HMAC_LENGTH, pn.paddingGen()); if(logMINOR) { String fragments = null; for(MessageFragment frag : packet.getFragments()) { if(fragments == null) fragments = String.valueOf(frag.messageID); else fragments = fragments + ", " + frag.messageID; Logger.minor(this, "Sending packet " + packet.getSequenceNumber() + " (" + data.length + " bytes) with fragments " + fragments + " and " + packet.getAcks().size() + " acks on "+this); packet.onSent(data.length, pn); if(packet.getFragments().size() > 0) { keyContext.sent(packet.getSequenceNumber(), packet.getLength()); if(packet.getFragments().size() == 0) { pn.onNotificationOnlyPacketSent(data.length); if(packet.getFragments().size() > 0) { if(timeLastSentPayload < now) timeLastSentPayload = now;
for(int ack : packet.getAcks()) { keyContext.ack(ack, pn, sessionKey); if(packet.getError() || (packet.getFragments().size() == 0)) { if(logMINOR) Logger.minor(this, "Not acking because " + (packet.getError() ? "error" : "no fragments")); dontAck = true; List<byte[]> l = packet.getLossyMessages(); if(l != null && !l.isEmpty()) pn.handleMessage(msg); for(MessageFragment fragment : packet.getFragments()) { if(messageWindowPtrReceived + MSG_WINDOW_SIZE > NUM_MESSAGE_IDS) { int upperBound = (messageWindowPtrReceived + MSG_WINDOW_SIZE) % NUM_MESSAGE_IDS; int seqno = packet.getSequenceNumber(); int acksQueued = keyContext.queueAck(seqno); boolean addedAck = acksQueued >= 0;
public void testSendCompletePacket() { NPFPacket p = new NPFPacket(); p.setSequenceNumber(2130706432); p.addAck(1000000, MAX_PACKET_SIZE); p.addAck(1000010, MAX_PACKET_SIZE); p.addAck(1000255, MAX_PACKET_SIZE); p.addAck(1000256, MAX_PACKET_SIZE); p.addAck(1000257, MAX_PACKET_SIZE); p.addAck(1005555, MAX_PACKET_SIZE); p.addAck(1005556, MAX_PACKET_SIZE); p.addAck(1005557, MAX_PACKET_SIZE); p.addAck(1005558, MAX_PACKET_SIZE); p.addAck(1005559, MAX_PACKET_SIZE); 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)); p.addMessageFragment(new MessageFragment(false, true, false, 4095, 14, 1024, 256, new byte[] { (byte)0xfd, (byte)0x47, (byte)0xc2, (byte)0x30, (byte)0x41, (byte)0x53, (byte)0x57, (byte)0x56,
public void testReceiveBadFragment() { byte[] packet = new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xC0, (byte)0x00, (byte)0x01, (byte)0x00}; NPFPacket r = NPFPacket.create(packet, pn); assertEquals(0, r.getFragments().size()); assertTrue(r.getError()); }
public void testSendPacketWithFragment() { NPFPacket p = new NPFPacket(); p.setSequenceNumber(100); 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)); byte[] correctData = new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x64, //Sequence number (100) (byte)0x00, (byte)0xB0, (byte)0x00, (byte)0x00, (byte)0x00, //Flags + messageID (byte)0x08, //Fragment length (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF}; checkPacket(p, correctData); }
public void testLength() { NPFPacket p = new NPFPacket(); p.addMessageFragment(new MessageFragment(true, false, true, 0, 10, 10, 0, new byte[10], null)); assertEquals(20, p.getLength()); //Seqnum (4), numAcks (1), msgID (4), length (1), data (10) p.addMessageFragment(new MessageFragment(true, false, true, 5000, 10, 10, 0, new byte[10], null)); assertEquals(35, p.getLength()); // + msgID (4), length (1), data (10) //This fragment adds 13, but the next won't need a full message id anymore, so this should only add 11 //bytes p.addMessageFragment(new MessageFragment(true, false, true, 2500, 10, 10, 0, new byte[10], null)); assertEquals(46, p.getLength()); }
public void testAckOnlyCreation() throws BlockedTooLongException, InterruptedException { BasePeerNode pn = new NullBasePeerNode(); NewPacketFormat npf = new NewPacketFormat(pn, 0, 0); PeerMessageQueue pmq = new PeerMessageQueue(); SessionKey s = new SessionKey(null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0), 1); 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 testLoadStatsLowLevel() throws BlockedTooLongException, InterruptedException { final byte[] loadMessage = new byte[] { (byte)0xFF, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBB, (byte)0xAA}; final SessionKey senderKey = new SessionKey(null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0), 1); NullBasePeerNode senderNode = new NullBasePeerNode() { @Override public MessageItem makeLoadStats(boolean realtime, boolean highPriority, boolean noRemember) { return new MessageItem(loadMessage, null, false, null, (short) 0, false, false); } @Override public SessionKey getCurrentKeyTracker() { return senderKey; } }; NewPacketFormat sender = new NewPacketFormat(senderNode, 0, 0); PeerMessageQueue senderQueue = new PeerMessageQueue(); senderQueue.queueAndEstimateSize(new MessageItem(new byte[128], null, false, null, (short) 0, false, true), 1024); Thread.sleep(PacketSender.MAX_COALESCING_DELAY*2); NPFPacket packet1 = sender.createPacket(512, senderQueue, senderKey, false); assertTrue(packet1 != null); assertEquals(1, packet1.getFragments().size()); assertEquals(1, packet1.getLossyMessages().size()); NPFPacketTest.checkEquals(loadMessage, packet1.getLossyMessages().get(0)); // Don't decode the packet because it's not a real message. }
synchronized(acks) { Iterator<Map.Entry<Integer, Long>> it = acks.entrySet().iterator(); while (it.hasNext() && packet.getLength() < maxPacketSize) { Map.Entry<Integer, Long> entry = it.next(); int ack = entry.getKey(); if(!packet.addAck(ack, maxPacketSize)) { if(logDEBUG) Logger.debug(this, "Can't add ack "+ack); break;
assertEquals(1, fragment1.getFragments().size()); receiver.handleDecryptedPacket(fragment1, receiverKey); assertEquals(1, fragment2.getFragments().size()); receiver.handleDecryptedPacket(fragment2, receiverKey); assertEquals(2, ack1.getAcks().size()); assertEquals(0, (int)ack1.getAcks().first()); assertEquals(1, (int)ack1.getAcks().last()); sender.handleDecryptedPacket(ack1, senderKey); assertEquals(1, fragment3.getFragments().size()); receiver.handleDecryptedPacket(fragment3, receiverKey); 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());
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; offset = tryParseLossyMessages(packet, plaintext, offset); break;
public void testReceiveUnknownMessageLength() throws BlockedTooLongException { NullBasePeerNode senderNode = new NullBasePeerNode(); NewPacketFormat sender = new NewPacketFormat(senderNode, 0, 0); PeerMessageQueue senderQueue = new PeerMessageQueue(); NullBasePeerNode receiverNode = new NullBasePeerNode(); NewPacketFormat receiver = new NewPacketFormat(receiverNode, 0, 0); SessionKey senderKey = new SessionKey(null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0), 1); SessionKey receiverKey = new SessionKey(null, null, null, null, null, null, null, null, new NewPacketFormatKeyContext(0, 0), 1); senderQueue.queueAndEstimateSize(new MessageItem(new byte[1024], null, false, null, (short) 0, false, false), 1024); 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(fragment3, receiverKey); receiver.handleDecryptedPacket(fragment2, receiverKey); assertEquals(1, receiver.handleDecryptedPacket(fragment1, receiverKey).size()); }
/** Must NOT modify buf contents. */ private NPFPacket decipherFromSeqnum(byte[] buf, int offset, int length, SessionKey sessionKey, int sequenceNumber) { BlockCipher ivCipher = sessionKey.ivCipher; byte[] IV = new byte[ivCipher.getBlockSize() / 8]; System.arraycopy(sessionKey.ivNonce, 0, IV, 0, IV.length); IV[IV.length - 4] = (byte) (sequenceNumber >>> 24); IV[IV.length - 3] = (byte) (sequenceNumber >>> 16); IV[IV.length - 2] = (byte) (sequenceNumber >>> 8); IV[IV.length - 1] = (byte) (sequenceNumber); ivCipher.encipher(IV, IV); byte[] payload = Arrays.copyOfRange(buf, offset + HMAC_LENGTH, offset + length); byte[] hash = Arrays.copyOfRange(buf, offset, offset + HMAC_LENGTH); byte[] localHash = Arrays.copyOf(HMAC.macWithSHA256(sessionKey.hmacKey, payload), HMAC_LENGTH); if (!MessageDigest.isEqual(hash, localHash)) { if (logMINOR) { Logger.minor(this, "Failed to validate the HMAC using TrackerID="+sessionKey.trackerID); } return null; } PCFBMode payloadCipher = PCFBMode.create(sessionKey.incommingCipher, IV); payloadCipher.blockDecipher(payload, 0, payload.length); NPFPacket p = NPFPacket.create(payload, pn); NewPacketFormatKeyContext keyContext = sessionKey.packetContext; synchronized(this) { if(seqNumGreaterThan(sequenceNumber, keyContext.highestReceivedSeqNum, 31)) { keyContext.highestReceivedSeqNum = sequenceNumber; } } return p; }
public void testReceiveZeroLengthFragment() { byte[] packet = new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xB0, (byte)0x00, (byte) 0x00, (byte) 0x00, (byte)0x00}; NPFPacket r = NPFPacket.create(packet, pn); assertFalse(r.getError()); assertEquals(1, r.getFragments().size()); MessageFragment f = r.getFragments().get(0); assertEquals(0, f.fragmentLength); assertEquals(0, f.fragmentData.length); assertEquals(0, f.messageID); }