org.pcap4j.packet.AbstractPacket Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pcap4j-core Show documentation
Show all versions of pcap4j-core Show documentation
The core module of Pcap4J.
/*_##########################################################################
_##
_## Copyright (C) 2011-2017 Pcap4J.org
_##
_##########################################################################
*/
package org.pcap4j.packet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.pcap4j.util.ByteArrays;
import org.pcap4j.util.LazyValue;
import org.pcap4j.util.LazyValue.BuildValueCommand;
/**
* Abstract immutable packet class.
* If you use {@link org.pcap4j.packet.factory.PropertiesBasedPacketFactory PropertiesBasedPacketFactory},
* this subclass must implement the following method:
* {@code public static Packet newPacket(byte[] rawData, int offset, int length)
* throws IllegalRawDataException}
*
* @author Kaito Yamada
* @since pcap4j 0.9.1
*/
public abstract class AbstractPacket implements Packet {
/**
*
*/
private static final long serialVersionUID = -3016622134481071576L;
private final LazyValue lengthCache;
private final LazyValue rawDataCache;
private final LazyValue hexStringCache;
private final LazyValue stringCache;
private final LazyValue hashCodeCache;
/**
*
*/
public AbstractPacket() {
this.lengthCache
= new LazyValue(
new BuildValueCommand() {
@Override
public Integer buildValue() {
return calcLength();
}
}
);
this.rawDataCache
= new LazyValue(
new BuildValueCommand() {
@Override
public byte[] buildValue() {
return buildRawData();
}
}
);
this.hexStringCache
= new LazyValue(
new BuildValueCommand() {
@Override
public String buildValue() {
return buildHexString();
}
}
);
this.stringCache
= new LazyValue(
new BuildValueCommand() {
@Override
public String buildValue() {
return buildString();
}
}
);
this.hashCodeCache
= new LazyValue(
new BuildValueCommand() {
@Override
public Integer buildValue() {
return calcHashCode();
}
}
);
}
/**
* Returns the Header object representing this packet's header.
* This subclass have to override this method if the packet
* represented by the subclass has a header.
*/
@Override
public Header getHeader() { return null; }
/**
* Returns the Packet object representing this packet's payload.
* This subclass have to override this method if the packet
* represented by the subclass has a payload.
*/
@Override
public Packet getPayload() { return null; }
/**
* This method calculates the value {@link #length length()} will return by
* adding up the header length and the payload length.
* If you write this subclass which represents a packet with extra parts (e.g. a trailer),
* you need to override this method.
*
* @return a calculated length
*/
protected int calcLength() {
int length = 0;
if (getHeader() != null) {
length += getHeader().length();
}
if (getPayload() != null) {
length += getPayload().length();
}
return length;
}
/**
* Returns the packet length in bytes.
* This method calls {@link #calcLength calcLength()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public int length() {
return lengthCache.getValue();
}
/**
* This method builds the value {@link #getRawData getRawData()} will return by
* concatenating the header's raw data and the payload's raw data.
* If you write this subclass which represents a packet with extra parts (e.g. a trailer),
* you need to override this method.
*
* @return a raw data built
*/
protected byte[] buildRawData() {
byte[] rd = new byte[length()];
Header header = getHeader();
Packet payload = getPayload();
int dstPos = 0;
if (header != null) {
System.arraycopy(
getHeader().getRawData(), 0, rd, 0, header.length()
);
dstPos += header.length();
}
if (payload != null) {
System.arraycopy(
getPayload().getRawData(), 0, rd, dstPos, payload.length()
);
dstPos += payload.length();
}
return rd;
}
/**
* Returns this packet's raw data.
* This method calls {@link #buildRawData buildRawData()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
* More correctly, this method returns a copy of the cached value,
* so that the cache can't be changed.
*/
@Override
public byte[] getRawData() {
byte[] rawData = rawDataCache.getValue();
byte[] copy = new byte[rawData.length];
System.arraycopy(rawData, 0, copy, 0, copy.length);
return copy;
}
@Override
public Iterator iterator() {
return new PacketIterator(this);
}
@Override
public T get(Class clazz) {
for (Packet p: this) {
if (clazz.isInstance(p)) {
return clazz.cast(p);
}
}
return null;
}
@Override
public Packet getOuterOf(Class extends Packet> clazz) {
for (Packet p: this) {
if (clazz.isInstance(p.getPayload())) {
return p;
}
}
return null;
}
@Override
public boolean contains(Class clazz) {
return get(clazz) != null;
}
@Override
public abstract Builder getBuilder();
/**
* This method builds the value {@link #toHexString toHexString()} will return
* using the return value of {@link #getRawData getRawData()}.
* Each octet in this return value is separated by a white space.
* (e.g. 00 01 02 03 aa bb cc)
*
* @return a hex string representation of this object
*/
protected String buildHexString() {
return ByteArrays.toHexString(getRawData(), " ");
}
/**
* Returns the hex string representation of this object.
* This method calls {@link #buildHexString buildHexString()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*
* @return a hex string representation of this object
*/
public String toHexString() {
return hexStringCache.getValue();
}
/**
* This method builds the value {@link #toString toString()} will return by
* concatenating the header's string representation and the payload's string representation.
* If you write this subclass which represents a packet with extra parts (e.g. a trailer),
* you need to override this method.
*
* @return a string representation of this object
*/
protected String buildString() {
StringBuilder sb = new StringBuilder();
if (getHeader() != null) {
sb.append(getHeader().toString());
}
if (getPayload() != null) {
sb.append(getPayload().toString());
}
return sb.toString();
}
/**
* Returns a string representation of the object.
* This method calls {@link #buildString buildString()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public String toString() {
return stringCache.getValue();
}
/**
* Indicates whether some other object is "equal to" this one.
* This method firstly compares this packet's header using
* the header's equals(Object) method, then compares this packet's payload
* using the payload's equals(Object) method.
* If you write this subclass with fields which represent
* somethings other than header or payload,
* you need to override this method.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) { return true; }
if (!this.getClass().isInstance(obj)) { return false; }
Packet other = (Packet)obj;
if (this.getHeader() == null || other.getHeader() == null) {
if (!(this.getHeader() == null && other.getHeader() == null)) {
return false;
}
}
else {
if (!this.getHeader().equals(other.getHeader())) { return false; }
}
if (this.getPayload() == null || other.getPayload() == null) {
if (!(this.getPayload() == null && other.getPayload() == null)) {
return false;
}
else {
return true;
}
}
else {
return this.getPayload().equals(other.getPayload());
}
}
/**
* This method calculates the value {@link #hashCode hashCode()} will return using
* the header's hash code and the payload's hash code.
* If you write this subclass which represents a packet with extra parts (e.g. a trailer),
* you need to override this method.
*
* @return a calculated hash code value for the object
*/
protected int calcHashCode() {
int result = 17;
if (getHeader() != null) {
result = 31 * result + getHeader().hashCode();
}
if (getPayload() != null) {
result = 31 * result + getPayload().hashCode();
}
return result;
}
/**
* Returns a hash code value for the object.
* This method calls {@link #calcHashCode calcHashCode()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public int hashCode() {
return hashCodeCache.getValue();
}
/**
* Abstract packet builder class.
*
* @author Kaito Yamada
* @version pcap4j 0.9.9
*/
public static abstract class AbstractBuilder implements Builder {
@Override
public Iterator iterator() {
return new BuilderIterator(this);
}
@Override
public T get(Class clazz) {
for (Builder b: this) {
if (clazz.isInstance(b)) {
return clazz.cast(b);
}
}
return null;
}
@Override
public Builder getOuterOf(Class extends Builder> clazz) {
for (Builder b: this) {
if (clazz.isInstance(b.getPayloadBuilder())) {
return b;
}
}
return null;
}
@Override
public AbstractBuilder payloadBuilder(Builder payloadBuilder) {
throw new UnsupportedOperationException();
}
@Override
public Builder getPayloadBuilder() { return null; }
@Override
public abstract Packet build();
}
/**
* Abstract immutable header class.
*
* @author Kaito Yamada
* @version pcap4j 0.9.1
*/
public static abstract class AbstractHeader implements Header {
/**
*
*/
private static final long serialVersionUID = -8916517326403680608L;
private final LazyValue lengthCache;
private final LazyValue rawDataCache;
private final LazyValue hexStringCache;
private final LazyValue stringCache;
private final LazyValue hashCodeCache;
/**
*
*/
protected AbstractHeader() {
this.lengthCache
= new LazyValue(
new BuildValueCommand() {
@Override
public Integer buildValue() {
return calcLength();
}
}
);
this.rawDataCache
= new LazyValue(
new BuildValueCommand() {
@Override
public byte[] buildValue() {
return buildRawData();
}
}
);
this.hexStringCache
= new LazyValue(
new BuildValueCommand() {
@Override
public String buildValue() {
return buildHexString();
}
}
);
this.stringCache
= new LazyValue(
new BuildValueCommand() {
@Override
public String buildValue() {
return buildString();
}
}
);
this.hashCodeCache
= new LazyValue(
new BuildValueCommand() {
@Override
public Integer buildValue() {
return calcHashCode();
}
}
);
}
/**
* Returns a list of byte arrays which represents this header's fields.
* This method is called by {@link #calcLength calcLength()}
* and {@link #buildRawData buildRawData()}.
*
* @return a list of byte arrays which represents this header's fields
*/
protected abstract List getRawFields();
/**
* This method calculates the value {@link #length length()} will return by
* adding up the lengths of byte arrays in the list
* {@link #getRawFields getRawFields()} returns.
*
* @return a calculated length
*/
protected int calcLength() {
int length = 0;
for (byte[] rawField: getRawFields()) {
length += rawField.length;
}
return length;
}
/**
* Returns the header length in bytes.
* This method calls {@link #calcLength calcLength()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public int length() {
return lengthCache.getValue();
}
/**
* This method builds the value {@link #getRawData getRawData()} will return by
* concatenating the byte arrays in the list
* {@link #getRawFields getRawFields()} returns.
*
* @return a raw data built
*/
protected byte[] buildRawData() {
return ByteArrays.concatenate(getRawFields());
}
/**
* Returns this header's raw data.
* This method calls {@link #buildRawData buildRawData()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
* More correctly, this method returns a copy of the cached value,
* so that the cache can't be changed.
*/
@Override
public byte[] getRawData() {
byte[] rawData = rawDataCache.getValue();
byte[] copy = new byte[rawData.length];
System.arraycopy(rawData, 0, copy, 0, copy.length);
return copy;
}
/**
* This method builds the value {@link #toHexString toHexString()} will return
* using the return value of {@link #getRawData getRawData()}.
* Each octet in this return value is separated by a white space.
* (e.g. 00 01 02 03 aa bb cc)
*
* @return a hex string representation of this object
*/
protected String buildHexString() {
return ByteArrays.toHexString(getRawData(), " ");
}
/**
* Returns the hex string representation of this object.
* This method calls {@link #buildHexString buildHexString()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*
* @return a hex string representation of this object
*/
public String toHexString() {
return hexStringCache.getValue();
}
/**
* This method builds the value {@link #toString toString()} will return.
*
* @return a string representation of this object
*/
protected String buildString() {
StringBuilder sb = new StringBuilder();
String ls = System.getProperty("line.separator");
sb.append("[A header (")
.append(length())
.append(" bytes)]")
.append(ls);
sb.append(" Hex stream: ")
.append(ByteArrays.toHexString(getRawData(), " "))
.append(ls);
return sb.toString();
}
/**
* Returns a string representation of the object.
* This method calls {@link #buildString buildString()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public String toString() {
return stringCache.getValue();
}
/**
* Indicates whether some other object is "equal to" this one using
* return values of {@link #getRawData getRawData()}.
* This method should be overridden so that it does more strict comparisons
* more efficiently.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) { return true; }
if (!this.getClass().isInstance(obj)) { return false; }
return Arrays.equals(getClass().cast(obj).getRawData(), getRawData());
}
/**
* This method builds the value {@link #hashCode hashCode()} will return using
* the byte array {@link #getRawData getRawData()} returns.
* This method may be better to be overridden for performance reason.
*
* @return a calculated hash code value for the object
*/
protected int calcHashCode() {
return Arrays.hashCode(getRawData());
}
/**
* Returns a hash code value for the object.
* This method calls {@link #calcHashCode calcHashCode()} and caches the return value
* when it is called for the first time,
* and then, this method returns the cached value from the second time.
*/
@Override
public int hashCode() {
return hashCodeCache.getValue();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy