All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pcap.codec.ip.ip6.Fragment Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/** This code is licenced under the GPL version 2. */
package pcap.codec.ip.ip6;

import java.util.HashMap;
import java.util.Map;
import pcap.codec.AbstractPacket;
import pcap.codec.Packet;
import pcap.codec.TransportLayer;
import pcap.common.annotation.Inclubating;
import pcap.common.memory.Memory;
import pcap.common.util.NamedNumber;
import pcap.common.util.Strings;
import pcap.common.util.Validate;

/** @author Ardika Rommy Sanjaya */
@Inclubating
public class Fragment extends AbstractPacket {

  private final Header header;
  private final Packet payload;
  private final Builder builder;

  private Fragment(final Builder builder) {
    this.header = new Header(builder);
    this.payloadBuffer = builder.payloadBuffer;
    if (this.payloadBuffer != null
        && this.payloadBuffer.readerIndex() < this.payloadBuffer.writerIndex()) {
      this.payload =
          TransportLayer.valueOf(header.payloadType().value()).newInstance(this.payloadBuffer);
    } else {
      this.payload = null;
    }
    this.builder = builder;
  }

  @Override
  public Header header() {
    return header;
  }

  @Override
  public Packet payload() {
    return payload;
  }

  @Override
  public Builder builder() {
    return builder;
  }

  @Override
  public Memory buffer() {
    return header().buffer();
  }

  @Override
  public String toString() {
    return Strings.toStringBuilder(this)
        .add("header", header)
        .add("payload", payload != null ? payload.getClass().getSimpleName() : "(None)")
        .toString();
  }

  public static final class Header extends AbstractPacket.Header {

    public static final int FIXED_FRAGMENT_HEADER_LENGTH = 8;

    private final TransportLayer nextHeader;
    private final short fragmentOffset;
    private final FlagType flagType;
    private final int identification;

    private final Builder builder;

    private Header(final Builder builder) {
      this.nextHeader = builder.nextHeader;
      this.fragmentOffset = builder.fragmentOffset;
      this.flagType = builder.flagType;
      this.identification = builder.identification;
      this.buffer = resetIndex(builder.buffer, length());
      this.builder = builder;
    }

    public TransportLayer nextHeader() {
      return nextHeader;
    }

    public int fragmentOffset() {
      return fragmentOffset & 0x1fff;
    }

    public FlagType flagType() {
      return flagType;
    }

    public int identification() {
      return identification;
    }

    @Override
    public TransportLayer payloadType() {
      return nextHeader;
    }

    @Override
    public int length() {
      return FIXED_FRAGMENT_HEADER_LENGTH;
    }

    @Override
    public Memory buffer() {
      if (buffer == null) {
        buffer = ALLOCATOR.allocate(length());
        buffer.writeByte(nextHeader.value());
        buffer.writeByte(0); // reserved
        buffer.writeShort((fragmentOffset & 0x1fff) << 3 | flagType.value() & 0x1);
        buffer.writeInt(identification);
      }
      return buffer;
    }

    @Override
    public Builder builder() {
      return builder;
    }

    @Override
    public String toString() {
      return Strings.toStringBuilder(this)
          .add("nextHeader", nextHeader)
          .add("fragmentOffset", fragmentOffset)
          .add("flagType", flagType)
          .add("identification", identification)
          .toString();
    }
  }

  public static final class Builder extends AbstractPacket.Builder {

    private TransportLayer nextHeader;
    private short fragmentOffset;
    private FlagType flagType;
    private int identification;

    private Memory buffer;
    private Memory payloadBuffer;

    public Builder nextHeader(TransportLayer nextHeader) {
      this.nextHeader = nextHeader;
      return this;
    }

    public Builder fragmentOffset(int fragmentOffset) {
      this.fragmentOffset = (short) (fragmentOffset & 0x1fff);
      return this;
    }

    public Builder flagType(FlagType flagType) {
      this.flagType = flagType;
      return this;
    }

    public Builder identification(int identification) {
      this.identification = identification;
      return this;
    }

    @Override
    public Fragment build() {
      return new Fragment(this);
    }

    @Override
    public Fragment build(final Memory buffer) {
      resetIndex(buffer);
      this.nextHeader = TransportLayer.valueOf(buffer.readByte());
      buffer.readByte(); // reserved
      short sscratch = buffer.readShort();
      this.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
      this.flagType = FlagType.valueOf((byte) (sscratch & 0x1));
      this.identification = buffer.readInt();
      this.buffer = buffer;
      this.payloadBuffer = buffer.slice();
      return new Fragment(this);
    }

    @Override
    public Builder reset() {
      return reset(readerIndex, Header.FIXED_FRAGMENT_HEADER_LENGTH);
    }

    @Override
    public Builder reset(int offset, int length) {
      if (buffer != null) {
        Validate.notIllegalArgument(offset + length <= buffer.capacity());
        Validate.notIllegalArgument(nextHeader != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(fragmentOffset >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(flagType != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(identification >= 0, ILLEGAL_HEADER_EXCEPTION);
        int index = offset;
        buffer.setByte(index, nextHeader.value());
        index += 1;
        buffer.setByte(index, 0); // reserved
        index += 1;
        int sscratch = (fragmentOffset & 0x1fff) << 3 | flagType.value() & 0x1;
        buffer.setShort(index, sscratch);
        index += 2;
        buffer.setIndex(index, identification);
      }
      return this;
    }
  }

  public static final class FlagType extends NamedNumber {

    public static final FlagType LAST_FRAGMENT = new FlagType((byte) 0, "Last fragment.");

    public static final FlagType MORE_FRAGMENT = new FlagType((byte) 1, "More fragment.");

    public static final FlagType UNKNOWN = new FlagType((byte) -1, "UNKNOWN.");

    private static final Map REGISTRY = new HashMap<>();

    protected FlagType(Byte value, String name) {
      super(value, name);
    }

    public static FlagType register(final FlagType flagType) {
      REGISTRY.put(flagType.value(), flagType);
      return flagType;
    }

    /**
     * Get flag type from value.
     *
     * @param flag value.
     * @return returns {@link FlagType}.
     */
    public static FlagType valueOf(final byte flag) {
      FlagType flagType = REGISTRY.get(flag);
      if (flagType == null) {
        return UNKNOWN;
      }
      return flagType;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy