org.jnetstream.capture
Interface FileCapture<T extends FilePacket>

All Superinterfaces:
Capture<T>, java.io.Closeable, java.io.Flushable, java.lang.Iterable<T>
All Known Subinterfaces:
NapFile, PcapFile, SnoopFile

public interface FileCapture<T extends FilePacket>
extends java.io.Closeable, java.io.Flushable, Capture<T>

File capture extends the basic Capture interface and adds several capabilites which can only be done with files, as opposed to live captures for example. You can modify the contents of the file using FileCapture API and its supporting interface. You also have access to lower level API which works more closely with the structure of the file, such as records. At this lower level some knowledge of the file structure is neccessary and is explained in various API documentation sections. The file structure is still fairely abstracted and you may continue to work with generic records instead of specified ones.

Capture files contain network packet data captured from a network interface and stored in the file. The FileCapture interface provides an abstraction to the possible formats for capture files.

FileCapture extends the standard Capture interface and adds several methods that provide file related information.

 RecordIterator<BlockRecord> i = fileCapture.getBlockRecordIterator();
 
 if (i.hasNext() == false) {
        return;
 }
 
 BlockRecord block = i.next();
 
All capture files utilize a similar format that there is atleast 1 block record which contains 0 or more data records. Data records are typically packet records. There can also be other record types which hold various meta information such as counters and properties.
                                       
                                     RecordIterator<BlockRecord> blocks = fileCapture.getBlockRecordIterator();
                                       
                                     while (blocks.hasNext() {
                                     
                                      BlockRecord block = blocks.next();
                                      
                                      RecordIterator<DataRecord> i = block.getRecordIterator();
                                     
                                      while (i.hasNext()) {
                                        DataRecord record = i.next();
                                       
                                        System.out.printf("Record type=%s", record.getRecordType().toString());
                                      }
                                     }
                                       
 
The reason you aquire the block as an iterator is the certain formats have more than one block in the file. Most only have 1 though, so if you know that you are going to be working with a PCAP or SNOOP file, you can simply just aquire the block record immediately without putting everything in a loop. Notice that this extra level of inderection with the Block records is only neccessary when accessing records. The PacketIterator returns and manipulates packet records no matter which block they physicaly reside. You aquire the PacketIterator directly from the FileCapture.
 try {
        PacketIterator<FilePacket> i = fileCapture.getPacketIterator();
 
        while (i.hasNext()) {
                FilePacket packet = i.next();
                System.out.println(packet.toString());
        }
 } catch (IOException e) {
        e.printStackTrace();
 }
 
or the more compact Java 5 version:
                                   try {
                                     for (FilePacket packet: fileCapture) {
                                       System.out.println(packet.toString());
                                     }
                                   catch (IORuntimeException e) {
                                     e.ioException().printStackTrace();
                                   }
 
Notice that the second version throws IORuntimeException while the first throws the plain old IOException if any IO errors are encountered. This is because the normal java.util.Iterator and java.lang.Iterable interfaces do not provide a way to allow and applications throw any exceptions besides runtime exceptions. You still need to surround your loops around an iterator with try/catch statements in order to catch any IO errors thrown as a IORuntimeException.

Another way to access packets within a capture file is using the CaptureIndexer interface. The indexer provides a type of a List view of all the packets within the capture file. You use indexes to access a specific packet found within the file. Use the getPacketIndexer method to aquire a reference to an indexer of all the packets within the file.

The indexer only provides a view of the file, its typically not able to load all packets into memory from a file as some capture files can be very large. So the indexer pulls packets in and out of memory as neccessary when requested. For efficiency is goes a lot of caching of packets using SoftReferences. You must keep in mind, that any operation on the packet indexer may result in an IO operation, this has a performance and resource impact.

Both methods of accessing packets and records provide methods for modifying the capture file. Packets and records can be removed, switched, replaced and inserted anywhere within the file. All changes are first stored in memory and at certain points flushed to physical medium which is when the backend file gets physically modified. At anytime you can call on undoAllChanges method which discards all changes that have not been flushed and reverts to the original state of the file. If any changes had already been flushed to the file, those changes are not undone.

Author:
Mark Bednarczyk, Sly Technologies, Inc.

Method Summary
 void abortChanges()
           Method which abandons all currently cached and pending changes to the file contents.
 void flush()
          Changes to file content are cached for efficiency reasons.
 com.slytechs.utils.collection.IOSkippableIterator<? extends BlockRecord> getBlockIterator()
          Each capture file is organized so that there exists atleast 1 block record, usually at the beginning of the capture file.
 FastIterator getFastIterator()
           
 java.io.File getFile()
          Returns the underlying file object that is associated with this FileCapture.
 FormatType getFormatType()
          Gets the format type of this file.
 long getLength()
           Returns the length of the entire file including any changes that have been made.
 long getPacketCount()
           Returns the number of packets within the file.
 long getPacketCount(PacketCounterModel model)
          Gets the packet count using a different algorithm.
 PacketIndexer<T> getPacketIndexer()
          Indexer which accesses packets by index.
 PacketIterator<T> getPacketIterator()
           Packet iterator provides methods for mutation, searches and regular iteration over the entire file based capture.
 RawIndexer getRawIndexer()
          Raw ByteBuffer based record indexer.
 RawIterator getRawIterator()
          Gets an iterator that will return raw contents of the records contained in the underlying capture file.
 RawIterator getRawIterator(Filter<RecordFilterTarget> filter)
          Gets an iterator that will return raw contents of the records contained in the underlying capture file.
 RecordIndexer<? extends Record> getRecordIndexer()
          Indexer which accesses records by index.
 RecordIterator<? extends Record> getRecordIterator()
          Iterator which iterates over every record within the file capture.
 RecordIterator<? extends Record> getRecordIterator(Filter<RecordFilterTarget> filter)
          Iterator which iterates over every record within the file capture.
 com.slytechs.utils.number.Version getVersion()
          Returns the first file version found.
 boolean isEmpty()
          Tells if the capture file contains 0 packets.
 boolean isOpen()
          Checks if the current capture has an open connection to a physical file.
 java.nio.ByteOrder order()
          Gets the byte order of the underlying capture file.
 
Methods inherited from interface org.jnetstream.capture.Capture
getFilter, getType, isMutable, iterator
 

Method Detail

abortChanges

void abortChanges()
                  throws java.io.IOException

Method which abandons all currently cached and pending changes to the file contents. Initialy when a file is opened, no pending changes are waiting to be flushed, invoking the #abort method has no effect at this time. Once changes accumulate they continue to be cached until flushed, they can be aborted at any time and the file state is reverted back to the last flush call.

Any flushed changes that resulted in changes in the underlying capture file can not be undone and will remain. Only changes still in memory will be undone.

Throws:
java.io.IOException - any IO errors

flush

void flush()
           throws java.io.IOException
Changes to file content are cached for efficiency reasons. This flush method forces all the changes to be flushed to the file. This behaviour is file format specific as certain file formats provide different levels of capabilities and efficiency natively.

Specified by:
flush in interface java.io.Flushable
Throws:
java.io.IOException

getBlockIterator

com.slytechs.utils.collection.IOSkippableIterator<? extends BlockRecord> getBlockIterator()
                                                                                          throws java.io.IOException
Each capture file is organized so that there exists atleast 1 block record, usually at the beginning of the capture file. Block record, also sometimes called file header, contains 0 or more data records which hold some kind of information. The most common record type is packet record which has a record header and record data content which is the raw packet data.

Returns:
record iterator that will iterate over all block records within the capture file
Throws:
java.io.IOException

getFastIterator

FastIterator getFastIterator()

getFile

java.io.File getFile()
Returns the underlying file object that is associated with this FileCapture.

Returns:
underlying file object

getFormatType

FormatType getFormatType()
Gets the format type of this file.

Returns:
format of this file.

getLength

long getLength()

Returns the length of the entire file including any changes that have been made. This value may be different from the value returned from getFile().length() as some changes may still reside in memory and have not been flushed to physical storage.

However if you call abortChanges() and immediately after the call getFile().length() == getLength().

Returns:
real length of the entire file including any changes that have been made to it but not flushed.

getPacketCount

long getPacketCount()
                    throws java.io.IOException

Returns the number of packets within the file. This only includes records that hold packet data and not any additional meta data records. The method uses the default PacketCounter. If estimated packet counter is acceptable you can use one of of several other PacketCounterModels to calculate estimated packet count using the getPacketCount(PacketCounterModel) method.

The default PacketCounterModel is file type specific. The model at minimum returns an accurate count of packet records within the capture file, but no guarrantees about performance can be made and the performance will vary from format to format. You can use the more explicit getPacketCount(PacketCounterModel) method to counter packets.

Returns:
total number of packets within the file using the default model
Throws:
java.io.IOException - any io errors

getPacketCount

long getPacketCount(PacketCounterModel model)
                    throws java.io.IOException
Gets the packet count using a different algorithm. There are several different types of algorithms or PacketCounterModels to choose from, each has its own benefits and drawback. The reason that multiple algorithms are provided is that counting packets in a capture file can be extremely time consuming in large capture files since most capture files (with the exception of NAP) do not provide any sort of packet indexing or maintain a global count of packets within the entire file. Therefore the packets have to be in most cases iterated and counted. One of the models allows a statistical calculation upon the file which does not return a true packet count but is very close to the real number and in certain situations may be good enough.

Parameters:
model - model/algorithm to use to count packets
Returns:
number of packets calculated by the model
Throws:
java.io.IOException - any io exceptions

getPacketIndexer

PacketIndexer<T> getPacketIndexer()
                                                     throws java.io.IOException
Indexer which accesses packets by index. The elements returned by this indexer are FilePacket based objects.

Returns:
packet indexer
Throws:
java.io.IOException - any IO errors

getPacketIterator

PacketIterator<T> getPacketIterator()
                                                       throws java.io.IOException

Packet iterator provides methods for mutation, searches and regular iteration over the entire file based capture. Iterator keeps a current position in form of a cursor. Most of the methods work with the cursor either adjusting its position or using the cursor to learn the exact location where some operation should take place.

There is a special postion at the end of the file, past the last byte of file data. This location has a restriction on which operations may operate at this cursor position. For example you can no remove any elements at this location, but you can add which in effect is an append operation.

There may also be some restrictions on which operations are supported based on the FileMode using which the file capture was opened. In FileMode.ReadWrite or any such related modes, all operations are functional. In FileMode.ReadOnly or any such related modes, any operations which makes modifications may fail with a ReadonlyBuffer exception. You can use isMutable to check if the current file capture is opened in read-write mode.

Specified by:
getPacketIterator in interface Capture<T extends FilePacket>
Returns:
PacketIterator over FilePacket based elements
Throws:
java.io.IOException - Any IO errors while retrieving a packet

getRawIndexer

RawIndexer getRawIndexer()
                         throws java.io.IOException
Raw ByteBuffer based record indexer. The elements returned by this indexer are ByteBuffers which have the limit and position properties aligned to the beginning and end of recods. You access these records using list-like indexes. Raw indexer also allows some low level mutable methods.

Returns:
indexer which accesses raw records
Throws:
java.io.IOException - any IO errors

getRawIterator

RawIterator getRawIterator()
                           throws java.io.IOException
Gets an iterator that will return raw contents of the records contained in the underlying capture file.

Returns:
raw record iterator
Throws:
java.io.IOException - any IO errors

getRawIterator

RawIterator getRawIterator(Filter<RecordFilterTarget> filter)
                           throws java.io.IOException
Gets an iterator that will return raw contents of the records contained in the underlying capture file.

Parameters:
filter - record filter which will be applied to records during iteration
Returns:
raw record iterator
Throws:
java.io.IOException - any IO errors

getRecordIndexer

RecordIndexer<? extends Record> getRecordIndexer()
                                                 throws java.io.IOException
Indexer which accesses records by index. The elements returned by this indexer are Record based objects.

Returns:
record indexer
Throws:
java.io.IOException - any IO errors

getRecordIterator

RecordIterator<? extends Record> getRecordIterator()
                                                   throws java.io.IOException
Iterator which iterates over every record within the file capture. The iterator will iterate has range over every single record including the block record (i.e. file header) at the beginning of the file.

Returns:
Throws:
java.io.IOException

getRecordIterator

RecordIterator<? extends Record> getRecordIterator(Filter<RecordFilterTarget> filter)
                                                   throws java.io.IOException
Iterator which iterates over every record within the file capture. The iterator will iterate has range over every single record including the block record (i.e. file header) at the beginning of the file.

Parameters:
filter - a filter that will be applied to match packets during iteration
Returns:
Throws:
java.io.IOException

getVersion

com.slytechs.utils.number.Version getVersion()
                                             throws java.io.IOException
Returns the first file version found. There may be multiple blocks within the file at different versions.

Returns:
version of the file
Throws:
java.io.IOException

isEmpty

boolean isEmpty()
                throws java.io.IOException
Tells if the capture file contains 0 packets. This does not mean that the size of the file is 0, it still needs to contain valid Block record (file-header), but that it is a valid capture file with 0 packet records in it.

Returns:
true if file contains 0 records, with the exception of the block record which is required to establish a file type.
Throws:
java.io.IOException - any IO errors

isOpen

boolean isOpen()
Checks if the current capture has an open connection to a physical file. No IO operations are possible once the channel is closed.

Returns:
true means that the channel is open, false means its closed

order

java.nio.ByteOrder order()
Gets the byte order of the underlying capture file. The byte ordering only applies to the headers on various records that are used to store packet data. The byte ordering within the packet's data is protocol dependent and has no connection with the underlying storage's byte ordering scheme.

Returns:
byte ordering of the underlying storage