3.3 - Working with protocol headers

We have learned so far about how to check for headers, instantiate them and peer them so that we can read useful data out of them. But what are they?

A header is a java class essientially extends the JBuffer base class that is setup by the framework to point exactly at the data the header needs to access. So for example when ip header is discovered in a packet, we created a working instance of one Ip4 class, the header is peered with the packet buffer so that it only sees the part of the buffer where the header is supposed reside, that is starting at offset into the packet buffer at byte number 15 if we have a normal ethernet packet follows by ip header, which is usually the case. Ethernet header takes up 14 bytes that leave Ip4 header to start at exactly 15th byte.

The length of the ip4 header has also been already determined and the underlying JBuffer already bound to that portion of the buffer. Since typical Ip4 headers are exactly 20 bytes in length, when they do not contain any optional headers, our header and underlying header buffer is set to point exactly bytes 15-34 inclusive.

Let me stress this point again. Any protocol header definition has a JBuffer as a base class. So we could essentially just typecast any header to a JBuffer like this:

Ip4 ip = new Ip4();
if (packet.hasHeader(ip)) {
 JBuffer buffer = ip; // Automatic downcast since Ip4 extends JBuffer
}

If this was a normal ethernet packet as described in previous paragraph, we know that out byte 0 in our buffer is actually byte #15 into the overall packet buffer and the last byte in the buffer is #34. The buffer is bound to this range and we wouldn't be able to read any data at byte index less than 0 or greater than 34. We would see an exception thrown.

We can however read anything in between. We could do something like this, if we continue with our example:

Ip4 ip = new Ip4();
if (packet.hasHeader(ip)) {
 JBuffer buffer = ip; // Automatic downcast since Ip4 extends JBuffer

 if ( (buffer.getUByte(0) & 0xF0) != 0x40) {
   System.out.println("expected ip version number to be 4");
 }
 int hlen = (buffer.getUByte(0) & 0x0F) * 4;
 System.out.println("ip header length=" + hlen);
}

That is we are reading 0th byte out of the buffer where the first 4 bits of that value are the ip version number while the next 4 bits are header length in double words. So you can see, that any header is nothing more than a fancy JBuffer.

Now thinking back to our Ip4 header, it is much more convienient to provide an accessor method to the version and hlen fields of the ip header and coding that logic into the header definition. That is exactly what happens. Ip4 header utilizes the fact that it subclasses the JBuffer and simply uses the super.getUByte(0) & 0xF0 algorithm to read the value of the version field. Same applies to hlen() accessor and so forth. They simply read the requested field type directly out of the buffer they occupy and return the value back to the user.

Here is the extract from Ip4 header definition of these 2 simple fields:

public int version() {
  return getUByte(0) >> 4;
}

public int hlen() {
  return getUByte(0) & 0x0F;
}

Where the function getUByte(int) is defined in JBuffer class. All the hardwork of figuring out if the header is found in the packet, where it starts and how long it is, has already been done for you. Further more the header definition already contains all of the knowledge and know how on how to access each field for that particular header.