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());
  }
Beispiel #3
0
  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;
  }
Beispiel #4
0
  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());
  }