style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-7505528228218001"
data-ad-slot="1225241371">

2.7.1 - JBufferHandler and ByteBufferHandler

A handler that receives raw packet capture header and data. Both handlers work almost identically, where the handler's nextPacket() method receives either a JBuffer or ByteBuffer objects.

Exact signatures are:

class JBufferHandler<T>;
JBufferHandler.nextPacket(PcapHeader header, JBuffer buffer, T user);

Or the direct ByteBuffer alternative:

class ByteBufferHandler<T>;
ByteBufferHandler.nextPacket(PcapHeader header, ByteBuffer buffer, T user);

Where user is a user supplied object of T class type.

Here is the simplest example of how a handler is used:

StringBuilder errbuf = new StringBuilder();
Pcap pcap = Pcap.openOffline("tests/test-afs.pcap", errbuf);

JBufferHandler<String> handler = new JBufferHandler<String>() {
  public void nextPacket(PcapHeader header, JBuffer buffer, String user) {
    System.out.println("size of packet is=" + buffer.size());
  }
}

pcap.loop(10, handler, "jNetPcap rocks!");

pcap.close();

A ByteBufferHandler would look very similar:

StringBuilder errbuf = new StringBuilder();
Pcap pcap = Pcap.openOffline("tests/test-afs.pcap", errbuf);

ByteBufferHandler<String> handler = new ByteBufferHandler<String>() {
  public void nextPacket(PcapHeader header, ByteBufferBuffer buffer, String user) {
    System.out.println("size of packet is=" + buffer.capacity());
  }
}

pcap.loop(10, handler, "jNetPcap rocks!");

pcap.close();

In both cases, we use the loop() to setup the dispatch loop, we ask it to supply us with 10 packets, we register our call back handler, an anonymous class that we define inline and lastly we supply our user parameter which is a simple string.

In both cases, no data copies take place, not even for the 16 byte PcapHeader. The data is peered with the header and buffer at native level. This provides very fast access to data and in certain situations guarrantees that packet data is never copied all the way from the hardware capture device, our network interface, all the way to the end user application, our java program.

There is only one minor difference between a JBuffer and ByteBuffer based handlers. With every new packet received, a new ByteBuffer has to be allocated so that it can be peered with the packet data buffer. This is different with JBuffer implementation. It reuses the same JBuffer to deliver the packet to the user handler. That is only one instance of JBuffer is ever created and simply reused for every packet received. To be precise, a new JBuffer is allocated at the time the Pcap.loop() or Pcap.dispatch() is invoked, to handle that one call instance. Multiple invocations of the loop at the same time utilize different instances of JBuffer. This allows simple multi-threading capabilities and makes sure that they do not clobber each other's JBuffer peers.

This means, that the delivered buffers, are not suitable for permanent storage, even when putting on a simple short java collection's queue. The same is true for the ByteBuffer implementation. Even though a new ByteBuffer is allocated for every packet, the data it points to is at a libpcap revolving, round robin, buffer that is used to buffer packets before they are dispatched to the user's application. That means that those are also temporary packets and therefore not even the ByteBuffer can be kept for more than one iteration of the dispatch loop since it is unknown exactly when the buffer wraps around.

The only solution for longer storage is to reallocate the memory and copy the contents of both the data and the header. Both ByteBuffer and JBuffer classes provide method for fast native memory copies. JBuffer also works with JMemoryPool for efficient native memory management.

The copying of data is a time consuming operation and is delayed and left up to the user. The peering process itself is very light and fast. The user has great options for copying the data to permanent memory locations. More on that subject in another section.