The Artima Developer Community
Sponsored Link

Java Buzz Forum
Getting the Ethernet Frame

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Wilfred Springer

Posts: 176
Nickname: springerw
Registered: Sep, 2006

Wilfred Springer is a Software Architect at Xebia
Getting the Ethernet Frame Posted: Aug 13, 2009 10:47 AM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Wilfred Springer.
Original Post: Getting the Ethernet Frame
Feed Title: Distributed Reflections of the Third Kind
Feed URL: http://blog.flotsam.nl/feeds/posts/default/-/Java
Feed Description: Anything coming to my mind having to do with Java
Latest Java Buzz Posts
Latest Java Buzz Posts by Wilfred Springer
Latest Posts From Distributed Reflections of the Third Kind

Advertisement
A couple of days ago, I blogged about using Preon to take a Snoop file apart. It's interesting that it actually worked, but then again, it hardly retrieved any valuable data. Given that most of the data floating around on our networks is actually ethernet based, it would be nice if Preon would actually be able to take apart the data sections as well.

Obviously, I wouldn't be telling you all of this, if Preon would not be able to do that. So let me show you how. The full code is listed below.

The important bits are in line 60.

The code that we used to have there was this:

@Slice(size="(packetRecordLength - 24) * 8")
@BoundList(size="includedLength")
private byte[] packetData;

In the new version of SnoopFile, that changed into:

@Slice(size = "(packetRecordLength - 24) * 8")
@BoundObject(selectFrom = @Choices(alternatives =
@Choice(condition = "outer.header.datalinkType==DatalinkType.ETHERNET", type = EthernetFrame.class))
)
private Object packetData;

Basically, instead of decoding the packet data into a byte array, it's now immediately turned into an object. An object that actually has the relevant data already decoded. Now, don't be alarmed by the type of packetData. In the new code it's declared to be of type java.lang.Object. That's just to make sure that it will be able to cover for all of the types of packet data that you could possibly encounter. In the common case, it will be ethernet frames. But Snoop is able to capture data for other data link types as well, and it's fairly unlikely that these different types of packet data would have commonalities to be captured in a base class.

So, even thought he type of packetData is java.lang.Object, Preon will actually decode packet data in objects of a particular type, based on the data link type. The selectFrom attribute on @BoundObject contains the rules for picking the appropriate type of object. Currently, it only covers for Ethernet packages. It basically reads: if the data link type read as part of the header is Ethernet, then decode the data into an instance of EthernetFrame.

The EthernetFrame itself is defined like this:

public static class EthernetFrame {

@BoundList(size = "6")
private byte[] destinationAddress;

@BoundList(size = "6")
private byte[] sourceAddress;

@BoundNumber(size = "16")
private int type;

@BoundList(size="outer.includedLength - (6 + 6 + 2)")
private byte[] data;

}

Not much to explain here. It's pretty much straightforward Preon code. Note that the number of bytes is calculated based on an attribute of the packet record. Since the EthernetFrame is read as part of the PacketRecord, you *can* actually refer to the 'outer' context, and reference attributes of that outer context.

public class SnoopFile {

@Bound
private FileHeader header;

@BoundList(type = PacketRecord.class)
private List<PacketRecord> records;

public FileHeader getHeader() {
return header;
}

public List<PacketRecord> getRecords() {
return records;
}

public static class FileHeader {

@BoundBuffer(match = { 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00, 0x00, 0x00 })
private byte[] identificationPattern;

@BoundNumber(byteOrder = ByteOrder.BigEndian)
private int versionNumber;

@BoundNumber(size = "32", byteOrder = ByteOrder.BigEndian)
private DatalinkType datalinkType;

public int getVersionNumber() {
return versionNumber;
}

public DatalinkType getDatalinkType() {
return datalinkType;
}

}

@ImportStatic(DatalinkType.class)
public static class PacketRecord {

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long originalLength;

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long includedLength;

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long packetRecordLength;

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long cumulativeDrops;

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long timestampSeconds;

@BoundNumber(byteOrder = ByteOrder.BigEndian, size = "32")
private long timestampMicroseconds;

@Slice(size = "(packetRecordLength - 24) * 8")
@BoundObject(selectFrom = @Choices(alternatives = @Choice(condition = "outer.header.datalinkType==DatalinkType.ETHERNET", type = EthernetFrame.class)))
private Object packetData;

public long getOriginalLength() {
return originalLength;
}

public long getIncludedLength() {
return includedLength;
}

public long getPacketRecordLength() {
return packetRecordLength;
}

public long getCumulativeDrops() {
return cumulativeDrops;
}

public long getTimestampSeconds() {
return timestampSeconds;
}

public long getTimestampMicroseconds() {
return timestampMicroseconds;
}

public Object getPacketData() {
return packetData;
}

public static class EthernetFrame {

@BoundList(size = "6")
private byte[] destinationAddress;

@BoundList(size = "6")
private byte[] sourceAddress;

@BoundNumber(size = "16")
private int type;

@BoundList(size="outer.includedLength - (6 + 6 + 2)")
private byte[] data;

public String getDestinationAddress() {
return render(destinationAddress);
}

public String getSourceAddress() {
return render(sourceAddress);
}

private String render(byte[] address) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < address.length; i++) {
if (i != 0) {
builder.append(':');
}
builder.append(Integer.toHexString(0xff&address[i]));
}
return builder.toString();
}

}

}

public static enum DatalinkType {

@BoundEnumOption(0)
IEEE_802_3,

@BoundEnumOption(1)
IEEE_802_4_TOKEN_BUS,

@BoundEnumOption(2)
IEEE_802_5_TOKEN_RING,

@BoundEnumOption(3)
IEEE_802_6_METRO_NET,

@BoundEnumOption(4)
ETHERNET,

@BoundEnumOption(5)
HLDC,

@BoundEnumOption(6)
CHARACTER_SYNCHRONOUS,

@BoundEnumOption(7)
IBM_CHANNEL_TO_CHANNEL,

@BoundEnumOption(8)
FDDI,

@BoundEnumOption(9)
OTHER,

UNASSIGNED
}

}

Read: Getting the Ethernet Frame

Topic: Publicis to buy Microsoft's Razorfish in a deal valued at more than $500 million Previous Topic   Next Topic Topic: Job trends for the popular languages – Java, C++ and PHP

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use