libcoral - a C API for CoralReef

Introduction

Libcoral provides a C API for reading network interface devices and several different trace file formats, and for writing trace files. Some realistic examples of its use can be found in apps/utils/*.c in the distribution.

Libcoral operates on "sources", which include several types of live network interfaces/devices, and several types of tracefiles containing data recorded from one or more network interfaces/devices. The naming scheme for sources is described in the command usage document.

A typical program using libcoral has this basic structure:

  configure libcoral and one or more sources
  open sources
  start sources
  while (read block, cell or packet != NULL) {
      process the data we just read
      if (stop condition occurs) {
	  stop sources
      }
  }
  close sources

In the descriptions below, there are several pairs of functions with the same base name, with or without an "_all" suffix. The function suffixed with "_all" operates on all sources, and the other one operates on a single source indicated by the src parameter.

Compiling

All CoralReef programs should include these headers:

#include <stdio.h>
#include <sys/param.h>
#include <libcoral.h>
Note that <libcoral.h> will define fixed-width integer types (like uint32_t) if your system does not, since they are needed by many libcoral structures.

CoralReef programs should link with -lcoral, -lpcap (if libcoral was compiled with pcap support), and -lz (if libcoral was compiled with zlib support).

The API

Command-line Configuration

The following functions read coral commands from the command line or config files. The coral commands are described in the command usage document. These functions should only be called before coral_open() or coral_open_all().

You should call coral_set_api() before calling these functions to enable certain configuration commands. Also, you should set the defaults for configurable values with the coral_set functions before calling any of these functions, and (if needed) get the value after. This way, the option and its default value will appear in the coral_usage() message, and the user can override the defaults with command line options. If your application does not use a particular configurable value, you should leave it set to its initial value, so it will not appear in the coral_usage() message, and the coral_config functions will not allow it to be changed on the command line.

int coral_config_arguments(int argc, char *argv[]);
This function processes "-C" options and sourcename arguments contained in argv. Argv is a pointer to an array of strings containing the command line; argc is the number of strings in argv. For a description of Coral options, see the Command Usage documentation. A CoralReef source is created (with coral_new_source()) from each sourcename argument. If an option syntax error is encountered, this function prints a usage message. If other arguments are desired, use coral_config_options() instead and parse the arguments yourself; if other options are desired, parse the options and arguments yourself and call coral_config_command() for each "-C" option. Returns a non-negative integer for success, -1 for failure.

To limit the number of sources that will be allowed, call coral_set_max_sources() before calling this function.

For an example, see the end of this section.

int coral_config_options(int argc, char *argv[], const char *argmsg);
This function is like coral_config_arguments(), except it processes only the options, not the non-option arguments. If argmsg is NULL, this function assumes that arguments (other than Coral options) are not allowed, and considers it an error if other arguments are found; otherwise, other arguments (but not other options) are allowed. If successful, this function returns the index of the first non-option argument (so it would return 1 if there were no options, since argv[0] is the application name). It is the programmer's resposibility to handle the remaining command line arguments. If an error is encountered, this function returns -1, and prints a usage message with coral_usage(argv[0], "%s", argmsg). If other options are desired, use coral_config_command() instead. Returns a non-negative integer for success, -1 for failure.
int coral_config_command(const char *command);
Processes a config command. This function should be used instead of coral_config_options() or coral_config_arguments() if you need to accept your own options in addition to CoralReef options, or you want to accept CoralReef commands from inputs other than the command line. Returns 0 for success, -1 for failure.
int coral_config_file(const char *filename);
Process CoralReef commands in file filename. This is not usually needed if coral_config_arguments(), coral_config_options(), or coral_config_command() is used.
int coral_usage(const char *appname, const char *argmsg, ...);
Prints a message describing the command line syntax of a CoralReef application named appname. If argmsg is not NULL, it use used as a printf-style format for the arguments that follow, and the formatted result is appended to the syntax line. This is followed by descriptions of the CoralReef (-C) command line options.

Some example values for argmsg:

for an application that takes CoralReef options and no arguments:
NULL
for an application that takes CoralReef options and an optional argument
"[<argument>]"
for an application that takes -f, -bN, and CoralReef options, and one or more source arguments:
"[-f] [-b<N>] <source>..."

Examples

All these examples assume you will be using the packet API; you should change the argument of coral_set_api() as needed.

If only CoralReef options and sourcename arguments are needed, this simple code will do:

    coral_set_api(CORAL_API_PKT);
    if (coral_config_arguments(argc, argv) < 0)
        exit(-1);
If other options are desired, you must parse the options and arguments yourself, like this:
    int opt, foo_flag = 0, bar = 42;
    extern char *optarg;
    extern int optind;

    coral_set_api(CORAL_API_PKT);

    while ((opt = getopt(argc, argv, "C:fb:")) != -1) {
        switch (opt) {
        case 'C':
            if (coral_config_command(optarg) < 0)
                exit(-1);
            break;
        case 'f':
            foo_flag = 1;
            break;
        case 'b':
            bar = atoi(optarg);
            break;
        default:
            coral_usage(argv[0], "[-f] [-b<N>] <source>\n"
		"-f      foo flag\n"
		"-b<n>   bar value (default %d)\n",
		bar);
            exit(-1);
        }
    }

    while (optind < argc) {
        if (!coral_new_source(argv[optind]))
            exit(-1);
        optind++;
    }
If a bad option is given, this code will print a message like this to stderr, followed by descriptions of the CoralReef commands that are allowed for the configured API:
    Usage: app [-C <coral_command>]... [-f] [-b<N>] <source>...

Global Configuration

The following functions provide a way for the programmer to set global configuration values, including default values for the configuration of sources that have not yet been defined. The coral_set functions can be called before the coral_config functions to set default values that can be overridden on the command line or config file, and will be displayed in the coral_usage message. If the integer configuration values are set to a negative value, they will not be displayed in the coral_usage message. The coral_set functions can also be called after the coral_config functions so their values can't be overridden. They must not be called after sources are opened. The coral_set functions return 0 if successful, or -1 for failure; the coral_get functions return the value of the requested datum.

int coral_set_api(int api);
The api parameter to coral_set_api() must be CORAL_API_BLOCK, CORAL_API_CELL, or CORAL_API_PKT, optionally bitwise ORed with CORAL_API_WRITE. It initializes libcoral for use with the corresponding APIs, and should be called before any coral config, reading, or writing function.

Setting the APIs enables command line and configuration file options and functions that are specific to those APIs. Libcoral will generate an error if any disallowed option or function is attempted.

The api parameter should contain exactly one of the following constants:
API allowed configuration commands allowed functions
CORAL_API_BLOCK blocks
CORAL_API_CELL cells blocks deny
CORAL_API_PKT packets filter deny coral_add_pcap_filter()
Commands and functions not listed under any API are valid for all APIs.

The api parameter may optionally be bitwise-ORed with this constant, if coral_write will be used:
API allowed configuration commands allowed functions
CORAL_API_WRITE gzip coral_set_gzip()

Example: coral_set_api(CORAL_API_PKT | CORAL_API_WRITE);

int coral_set_max_sources(int n);
int coral_get_max_sources(void);
coral_set_max_sources() sets the maximum number of allowed Coral sources to n. It should be called before coral_config_arguments(), coral_config_options(), coral_config_command(), and coral_new_source() to restrict them. It returns 0 if successful, or -1 if n is negative or greater than 16. coral_get_max_sources() returns the maximum number of allowed Coral sources. The default max_sources value is 16.
int coral_set_options(int off, int on);
int coral_get_options(void);
coral_set_options() disables the options in the bitmask off and enables the options in the bitmask on. coral_get_options() returns a bitmask of currently enabled options. The options are:
CORAL_OPT_SORT_TIME (default: off)
Makes coral_read_cell_all() read cells in timestamp order. For this option to make sense, one of the following must be true: all interfaces have start epochs and were started at the same time, or all interfaces have unix epochs, or the CORAL_OPT_NORMALIZE_TIME option is on. If none of these conditions is true, libcoral will automatically enable the CORAL_OPT_NORMALIZE_TIME option.
CORAL_OPT_PARTIAL_PKT (default: on)
Allows coral_read_pkt() and coral_read_pkts() to handle partial packets.
CORAL_OPT_FATM_RAW_TIME (default: off)
Do not attempt to automatically correct the delayed firmware clock increment when the hardware clock wraps in the fatm card or skip cells prior to a clock reset in the first block. This can be used to improve performance if cell/packet timestamps will not be needed.
CORAL_OPT_POINT_RAW_TIME (default: off)
Do not attempt to automatically skip cells prior to a clock reset in the first block. This can be used to improve performance if cell/packet timestamps will not be needed.
CORAL_OPT_RAW_TIME
Equivalent to (CORAL_OPT_FATM_RAW_TIME | CORAL_OPT_POINT_RAW_TIME).
CORAL_OPT_NORMALIZE_TIME (default: on)
Make the result of the coral_read_clock relative to the unix epoch (1970-01-01 00:00:00 UTC); otherwise, the result will have some interface-dependant epoch. Normalizing is necessary when comparing times from multiple interfaces (this includes using CORAL_OPT_SORT_TIME) with different default epochs. But normalizing may introduce inaccuracy if the interfaces' hosts' CPU clocks are inaccurate, and may introduce additional processing overhead. The default epochs for the various types of interfaces are:
fatm
time of reset (e.g., by coral_start_all());
point
time of reset (e.g., by coral_start_all());
dag
the unix epoch (of the CPU used to do the capture)
pcap
the unix epoch (of the CPU used to do the capture)
tsh
either the unix epoch or the time of reset, depending on the original source of data (libcoral can identify the epoch automatically)
Traces from interfaces that don't natively use the unix epoch can only be normalized if the capture time was recorded in the trace. NLANR and MCI .crl traces do not contain capture time, although their filenames sometimes do, and CoralReef can use that; .crl traces made with CoralReef prior to 3.2.1 contain capture time only to the nearest second. Traces in .tsh format do not explicitly contain the capture time, but if the data timestamps are relative to the unix epoch, libcoral will use the first timestamp as the capture time; otherwise, libcoral will infer a capture time from the filename if possible.
CORAL_OPT_NO_FILTER (default: off)
Do not allow a pcap filter to be set by the coral_config functions. This is useful for applications that need to define their own filters.
CORAL_OPT_IP_CKSUM (default: off)
Tells coral_fmt_get_payload() to print and verify IP checksums.
int coral_set_iomode(int off, int on, int first, int fixed);
This function sets the default I/O mode of all subsequently defined sources. (To set the I/O mode of sources that have already been defined, use coral_source_set_iomode().)

The arguments to this function are:

off
bitmask of I/O mode flags to disable.
on
bitmask of I/O mode flags to enable.
first
specifies how many bytes to capture from each PDU (layer 2 packet/frame). If this parameter is negative, the configured value will be unchanged. For ATM interfaces, first will be rounded up to a multiple of ATM cell payload size (48 bytes). (In versions prior to 3.2, first was interpreted as cells instead of bytes on ATM interfaces.)
fixed
flag that prevents user from modifying the iomode via the command line or config file (this should be used before the coral_config functions, in applications with a non-configurable iomode).

The I/O mode flags:
flag equivalent CLI iomode description
CORAL_TX tx allow transmitting (not implemented)
CORAL_RX rx allow receiving
CORAL_RX_IDLE idle read all cells, including ATM idle cells
CORAL_RX_OAM ctrl read ATM OAM/RM cells
CORAL_RX_LAST last read last cell of each ATM AAL5 user PDU (packet)
CORAL_RX_USER_ALL user read all bytes of each packet or frame
CORAL_RX_ECHO echo retransmit received cells on devices which support it (always enabled on POINT cards)
CORAL_RX_UNKNOWN for traces, read whatever cells are in the trace file; for devices, use default mode (i.e., rx first=48). Setting this flag clears all other settings.

This function returns 0 for success, -1 for failure. It only affects sources that are created after it is called.

Setting first overrides a previously set CORAL_RX_USER_ALL flag, and setting the CORAL_RX_USER_ALL flag overrides a previously set first value. Attempting to set both at once has undefined results.

The default I/O mode is CORAL_RX, and first==48. Currently, an attempt to explicitly use an I/O mode to read a trace that does not match the I/O mode used to record the trace will generate a warning, but all the data in the trace will still be read. In a future release, the read functions may filter trace files according to the I/O mode (or generate an error if that is not possible).

For a summary of the iomode options supported by the various interface types, see the command usage document.

int coral_set_errfile(FILE *file);
int coral_set_errfilename(const char *filename);
FILE *coral_get_errfile(void);
coral_set_errfile() and coral_set_errfilename() set, the destination for future libcoral error and warning messages. file is an already opened stdio stream pointer, and filename is the name of a file that will be opened by libcoral. Any previously set error file will be closed only if it was set by name other than "-" (i.e., by coral_set_errfilename(), but not by coral_set_errfile()). If file or filename is NULL, stderr will be used. If filename is "-", stdout will be used. coral_get_errfile() returns the current message destination. The default message destination is stderr.
int coral_set_verbosity(int verbosity);
int coral_get_verbosity(void);
Set or get the verbosity level of libcoral and coral_diag(). If verbosity==0, only errors are printed; if verbosity==1 errors and warnings are printed. Meanings for values greater than 1 may be assigned by the programmer for use with coral_diag(). The default verbosity is 1. To completely disable coral messages, set the verbosity to -1.
int coral_set_max_pkts(uint64_t n);
int coral_set_max_cells(uint64_t n);
int coral_set_max_blks(uint64_t n);
uint64_t coral_get_max_pkts(void);
uint64_t coral_get_max_cells(void);
uint64_t coral_get_max_blks(void);
These functions get or set the maximum record count that will be read by the reading APIs. When the limit is reached, reading functions will indicate EOF. If set to zero, there is no limit. All three counts are zero by default.
count affected APIs
max_pkts packet
max_cells cell
max_blks block and cell
int coral_set_comment(const char *comment);
const char *coral_get_comment(void);
Set or get the default comment that will be written in the file header by the coral_write functions. The default comment may be overridden by coral_write_set_comment().
int coral_set_duration(long duration);
long coral_get_duration(void);
Set or get the duration value.

If the duration value is greater than 0, it determines how long libcoral will read from sources after they are started; after the duration has expired, the reading function will indicate EOF. Libcoral uses both real time and cell timestamps to test duration, so it will work with tracefiles and devices receiving live traffic.

With the default duration of -1, the coral_config functions will not allow duration to be set. To have your application not use duration by default, but still let the user override it, set it to 0 before calling the coral_config functions.

Before version 3.3.0, libcoral did not test duration when reading; the programmer was expected to handle it himself. Now, the programmer should do nothing other than enable it, and let libcoral's reading functions handle the duration.

Libcoral does not use SIGALRM to implement duration.

int coral_set_interval(struct timeval *interval);
int coral_get_interval(struct timeval *interval);
Set or get the interval value. If the interval has not yet been set, coral_get_interval() returns -1 and fills in *interval with { -1, -1 }; otherwise, it returns 0 and fills in *interval with the nonnegative interval value.

The interval value is never automatically used by libcoral; it just provides a convenient and consistent way to let the user set an interval on the command line or in a config file. The programmer may use the interval by passing the result of coral_get_interval() in as a parameter to coral_read_pkt_init() or coral_read_cell_i(). Libcoral uses cell timestamps to test for intervals, so the intervals it reports will be correct for both tracefiles and devices, although the act of reporting may be delayed because of internal buffering.

With the default interval of -1, the coral_config functions will not allow interval to be set. To have your application not use interval by default, but still let the user override it, set it to 0.0 before calling the coral_config functions.

Libcoral does not use SIGALRM to implement interval.

int coral_set_gzip(const str *mode);
If mode is NULL, coral_write_open() will not gzip files unless they end in ".gz". If mode is "", coral_write_open() will gzip files with the default parameters (compression level 1). If mode is a non-empty string, coral_write_open() will append it to the "wb" mode when calling gzopen(); see the zlib documentation for details.

Source Configuration

These functions define and configure sources. They may only be called before opening sources.
coral_source_t *coral_new_source(const char *sourcename);
Create a new coral source from sourcename. Sources are described in the Command usage document. Returns source pointer if successful, or NULL for failure. This function is useful for creating a source directly from the program (instead of through command line and config file with the coral_config functions).
coral_source_t *coral_new_fdsource(int fd, const char *sourcename);
Like coral_new_source, except that it uses the already-open file descriptor fd instead of a filename. If sourcename is not NULL, coral_open() will examine it for a prefix or suffix to determine how to interpret the data read from fd; otherwise, coral_open() will assume data from fd contains a CoralReef (crl) trace. This function is useful for creating a source directly from a file descriptor in the program; for example, a socket connected to another process that used coral_write_fdopen().

Mixing CoralReef operations with other operations on descriptor fd may have unpredictable effects.

int coral_source_set_iomode(coral_source_t *src, int off, int on, int first);
int coral_source_set_iomode_all(int off, int on, int first);
These functions modify the I/O mode of the indicated already defined sources. The off, on, and first arguments are identical to those of coral_set_iomode(). These functions return 0 for success, -1 for failure.

To set the default I/O mode of sources that have not yet been defined, use coral_set_iomode().

int coral_source_set_firmware(coral_source_t *src, const char *firmware);
int coral_source_set_firmware_all(const char *firmware);
Set the location of the firmware file of source src, or of all sources. The firmware will be loaded when the source is opened. Returns 0 for success, -1 for failure.

Opening

Sources must be opened and started before they can be read. When they are no longer needed, they may be stopped and should be closed. Note that failing to close a DAG card source may leave it in an unusable state (/proc/dag will report the device is "Busy"); the card must be re-initialized before CoralReef can read from it again.
int coral_open(coral_source_t *src);
int coral_open_all(void);
Open the indicated coral sources that have been created by coral_config_arguments(), coral_config_options(), coral_config_command(), and coral_new_source(), but do not start them. If successful, these functions return the number of interfaces opened. If unsuccessful, these functions return -1 and close the source which failed. Note that a single tracefile source may contain multiple interfaces.
int coral_start(coral_source_t *src);
int coral_start_all(void);
Start capture on interface(s) of the indicated coral sources which have been opened with coral_open() or coral_open_all(). Addtionally, coral_start_all() resets the clocks of all open interfaces that allow it, to synchronize them. A source can not be read until it is started with one of these functions. (Prior to version 3.3, it was not strictly necessary to start tracefile sources.)
int coral_stop_all(void);
int coral_stop(coral_source_t *src);
Stop capturing on all interfaces of the indicated device sources. Returns 0 for success, -1 for failure. After a source is stopped, it may still contain buffered data, which can be read until the reading function returns an EOF indication. These functions are not safe to call asynchronously (e.g., from a signal handler).

See also: coral_pkt_done.

int coral_close_all(void);
int coral_close(coral_source_t *src);
Close all interfaces of the indicated sources, after flushing any partially filled blocks. Returns 0 for success, -1 for failure.

Packet Reading

The packet reading functions may be used with any CoralReef interface that has been started. All time is measured against packet timestamps, so it works even for trace files that aren't in real time. See crl_print_pkt.c for a good example of using the packet API.

Single packet reading

int coral_read_pkt_init(coral_source_t *src, coral_iface_t *iface,
    struct timeval *interval);
Prepare to read packets from an open src or iface with coral_read_pkt(). If iface is not NULL, packets will be read from iface; otherwise, if src is not NULL, packets will be read from all interfaces of src; otherwise, packets will be read from all interfaces of all open sources. There is no restriction on reading multiple pcap sources or mixing pcap and OCx sources, as there was prior to version 3.4. If iface belongs to a source with multiple interfaces, data from the other interfaces of that source will be discarded. Packets can be read from only one set of sources at a time; calling coral_read_pkt_init() invalidates any sources that were previously initialized for packet reading. Interval is the amount of time coral_read_pkt() will wait between returning statistical information (measured against packet timestamps).

Because coral_read_pkt() implicitly sorts packets by timestamp, the packet timestamps must be comparable. If necessary, coral_read_pkt_init() will automatically enable the CORAL_OPT_NORMALIZE_TIME option to guarantee that the timestamps are comparable.

coral_read_pkt_init() returns 0 if successful, or -1 if an error occurs.

coral_iface_t *coral_read_pkt(coral_pkt_result_t *pkt_result,
    coral_interval_result_t *interval_result);
Read a packet from one of the interfaces which have been initialized with coral_read_pkt_init(). If a packet filter has been set, only packets that match the filter will be read. Packets read are always sorted by time, regardless of the setting of the CORAL_OPT_SORT_TIME option. If the CORAL_OPT_PARTIAL_PKT option is turned off, only complete packets will be read (but truncated packets are always counted by the truncated field of coral_pkt_stats_t).

pkt_result and interval_result are pointers to structures (allocated by the programmer) that will be filled in by the call. For success, coral_read_pkt() returns a pointer to the interface which was read, and the contents of the structures indicate what happened:

if (pkt_result->packet != NULL) {
A packet was read; information about the packet is contained in pkt_result.
pkt_result->packet will point to a coral_pkt_buffer_t containing the link layer (LLC/SNAP, ethernet, etc) PDU. On ATM interfaces, pkt_result->header will point to a coral_pkt_buffer_t containing the first 4 bytes of the ATM header of the last captured cell of the packet (in network byte order); pkt_result->trailer will point to a coral_pkt_buffer_t containing the AAL5 trailer (in network byte order), if available; and pkt_result->subiface will contain the ATM vpvc (in host byte order) from which the packet was read. On IEEE 802.3/Ethernet interfaces carrying IEEE 802.1Q VLAN traffic, pkt_result->subiface will be the VLAN ID. On other types of interfaces, pkt_result->header and pkt_result->trailer will be NULL, and pkt_result->subiface will be 0.
} else if (interval_result->stats == NULL) {
An interval has begun at time interval_result->begin. (interval_result->end is not valid.)
} else {
The interval begun at time interval_result->begin and ending at interval_result->end has ended. Statistics for the interval are contained in interval_result->stats.
}

If the interval specified in coral_read_pkt_init() was NULL or 0, interval_result may be NULL, and coral_read_pkt() will never return with pkt_result->packet == NULL. The beginning of an interval is not aligned to a multiple of the interval size. When reading from a live interface, internal buffering may cause reporting of the end of the interval to be delayed, but the data reported will cover exactly the requested interval. (In versions 3.2.x, the reported interval included "quiet" (trafficless) time after the end of the requested time. In versions 3.1 and earlier, the data reported included packets past the end of the interval that fell in the same internal buffer as the end of the interval.) Interval comparisons are made against packet timestamps, not a real clock, so the same results will be produced by reading a live interface or reading a trace taken on that interface in the same period.

The protocol of pkt_result->packet is determined by the interface type. For ATM interfaces, the protocol is determined by the virtual channel and proto configuration rules as by coral_proto_rule(). Note that if the configuration is incorrect, the packet buffer will not make sense. For TSH interfaces, the protocol for a valid packet is always CORAL_NETPROTO_IPv4, and IP options are always zero; the protocol of an invalid packet is CORAL_PROTO_UNKNOWN.

If coral_cell_block_hook points to a programmer-defined function, it will be called when a new block of ATM cells is read.

To indicate EOF, a stopped device, or expired duration, coral_read_pkt() returns NULL with errno == 0. For an error, coral_read_pkt() returns NULL with errno set to indicate the type of error. (Certain types of errors that were reported as EOF in versions prior 3.5 are now correctly reported as errors.)

If coral_get_verbosity() >= 1, then at the end of every interval, if there were any packet errors (nonzero fields in interval_result->stats) during the interval, coral_read_pkt() prints warnings to the error file. If intervals were not used, the warnings are printed only at EOF, covering the entire duration.

Callback loop packet reading

int coral_read_pkts(coral_source_t *src, coral_iface_t *iface,
		coral_pkt_handler pkthandler, 
		coral_pre_interval_handler preinthandler, 
		coral_post_interval_handler postinthandler,
		struct timeval *interval,
		void *mydata);
Reads packets from one or more interfaces, and calls a handler function for each packet read and for the beginning and end of each interval. Src, iface, and interval are interpreted as in coral_read_pkt_init(). coral_read_pkts() repeatedly reads link level packets (using coral_read_pkt()) until (coral_pkt_done != 0) or EOF is reached on all interfaces.

Pkthandler is a pointer to a function that will be called for each packet received.

Preinthandler and postinthandler are pointers to functions that will be called before and after each interval of approximately *interval seconds in which packets were received. Preinthandler and postinthandler are not called if they are NULL, interval is NULL, or *interval is less than or equal to 0.0.

Mydata will be passed as a parameter to the handler functions, but otherwise ignored; the programmer may use it as needed.

Postinthandler may set coral_pkt_done to nonzero to make coral_read_pkts() stop looping and return.

coral_read_pkts() returns 0 if it reaches EOF with no errors; or -1 if there is an error, with errno set to indicate the type of error. (Certain types of errors that were reported as EOF in versions prior 3.5 are now correctly reported as errors.)

typedef void (*coral_pkt_handler)(coral_iface_t *iface,
    const coral_timestamp_t *timestamp, void *mydata,
    coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
coral_pkt_handler is the type of the function called each time coral_read_pkts() reads a packet. Parameters:
iface
a pointer to the interface from which the packet was read.
timestamp
the time at which the packet was read (usable with the coral_read_clock functions).
mydata
the mydata parameter that was passed to coral_read_pkts().
packet
a pointer to a coral_pkt_buffer_t containing a link level packet, not including a trailer.
header
a pointer to a coral_pkt_buffer_t containing the header used at a next lower layer, or NULL. Currently, this is only used for the ATM header of the last received cell in the packet; the ATM header will be in network byte order (in version 3.1, this was in host byte order).
trailer
a pointer to a coral_pkt_buffer_t containing the trailer used at a next lower layer, if the lower layer uses trailers and the packet was not truncated; otherwise, NULL. Currently, this is only used for the ATM AAL5 trailer.
typedef void (*coral_pre_interval_handler)(coral_iface_t *iface,
	const struct timeval *begin, void *mydata);
typedef void (*coral_post_interval_handler)(coral_iface_t *iface,
	const struct timeval *begin, const struct timeval *end,
	void *mydata, const coral_pkt_stats_t *stats);
coral_pre_interval_handler and coral_post_interval_handler are the types of the functions called before and after (respectively) each interval of coral_read_pkts(). Parameters:
iface
the interface being read.
begin
the beginning of the interval.
mydata
the mydata parameter that was passed to coral_read_pkts()
stats
a pointer to a structure containing statistics about the interval, summed across all interfaces. (To get statistics for an individual interface, use coral_get_iface_stats().)

Other packet reading features

const coral_pkt_stats_t *coral_get_iface_stats(coral_iface_t *iface)
Returns a pointer to the coral_pkt_stats_t structure for iface for the most recent interval.
extern volatile int coral_pkt_done;
This can be set to a non-zero value at any time (e.g., in postblkhandler or in a signal handler) to force either packet reading function to act like it has detected EOF the next time it is called, on both device and trace file sources.

See also: coral_stop_all().

extern int (*coral_pkt_atm_hook)(const coral_iface_t *iface,
	const coral_pkt_buffer_t *packet, const coral_atm_cell_t *cell);
If coral_pkt_atm_hook is not NULL, the function to which it points is called each time the first cell of an AAL5 PDU is seen by coral_read_pkt() or coral_read_pkts() on an ATM interface. If this function returns 0, the packet reader function will skip the packet to which the cell belongs; if it returns nonzero, or the function pointer is NULL, the packet reader function will process the packet normally. The coral_pkt_atm_hook test is done before any reassembly is performed, so it is more efficient to discard packets in coral_pkt_atm_hook than after coral_read_pkt() returns or in the coral_pkt_handler of coral_read_pkts(). The parameters are:
iface
pointer to the interface from which the cell was read
packet
pointer to a packet structure containing as much data about the data link level packet as was available in the first cell. This is provided for convenient use with functions that take a coral_pkt_buffer_t parameter (e.g., coral_get_payload()).
cell
pointer to the first cell (in network byte order).
The default value of coral_pkt_atm_hook is NULL.

See also: coral_add_pcap_filter() and coral_pcap_setfilter().

int coral_get_payload(const coral_pkt_buffer_t *src, coral_pkt_buffer_t *dst);
src is a pointer to a coral_pkt_buffer_t containing a datagram or packet (e.g., packet_result->packet from coral_read_pkt()) with src->caplen > 0. coral_get_payload() skips past the lower level (outer) protocol encapsulation in src and fills in dst with information about the payload of src (see coral_pkt_buffer_t). If coral_get_payload() understands the src protocol but does not recognize the protocol of the payload, dst->protocol will contain CORAL_PROTO_UNKNOWN or some other undefined value.

coral_get_payload() returns 0 if it successfully parsed the src protocol information, or one of the following negative error codes:

CORAL_ENOPROTO
libcoral does not support the protocol
CORAL_ELENGTH
protocol information was truncated
CORAL_ESYNTAX
packet data are inconsistent with protocol
CORAL_ERROR
other error
The recognized protocols are listed in the Protocols section of the Command Usage document. Protocol identifiers are formed by concatenating "CORAL_", the prefix, and the name; e.g., CORAL_DLT_ATM_RFC1483.

This function treats IPv6 extension headers as encapsulated protocols. So, for example, say you have an Ethernet frame containing an IPv6 packet with a Routing header, Fragment header, and UDP datagram. If you call coral_get_payload() with that packet as src, and then repeatedly with the dst of the previous call as the src of the next, the value of dst->protocol after each successive call would be CORAL_NETPROTO_IPv6, CORAL_IPPROTO_ROUTING, CORAL_IPPROTO_FRAGMENT, CORAL_IPPROTO_UDP, and CORAL_PROTO_UNKNOWN, respectively.

Note: TSH files contain IPv4 packet headers only, and when CoralReef reads an IPv4 packet from a TSH file it fills the missing IP options (if any) with zeros to create a syntactically valid substring of an IP packet.

int coral_fmt_get_payload(const coral_pkt_buffer_t *src,
    coral_pkt_buffer_t *dst, char *buf, int len);
coral_fmt_get_payload() is like coral_get_payload(), except that it also writes up to len characters (including a terminating null character) of human-readable information about the lower level protocol into buf. Returns a nonnegative number if successful, or -1 for any of the following errors: vsnprintf() is not available on your system and buf is not NULL; or any of the errors listed in the documentation for coral_get_payload().

The information written into buf attempts to cover all relevant information about the protocol. Irrelevant information is omitted for brevity (for example: for TCP, the urgent pointer is printed only if the URG flag is set; for IPv4, type-of-service is printed only if it is nonzero, and the fragment offset is printed only if the packet is a fragment). The IP checksum will be printed and verified only if the CORAL_OPT_IP_CKSUM option is set.

int coral_get_payload_by_proto(const coral_pkt_buffer_t *src,
    coral_pkt_buffer_t *dst, coral_protocol_t proto);
int coral_get_payload_by_layer(const coral_pkt_buffer_t *src,
    coral_pkt_buffer_t *dst, int layer);
These functions search for the outermost packet in src whose protocol is proto or protocol layer is layer, and copy that packet's information to dst. The copied packet will be src itself if its protocol matches the criterion; otherwise these functions repeatedly call coral_get_payload() to find encapsulated packets. These functions return 0 if successful, or -1 if the proto or layer is not found, or for any of the errors listed in the documentation for coral_get_payload().
const char *coral_get_net_pkt(const coral_pkt_buffer_t *buffer, int *protocol);
Obsolete. See coral_get_payload()

Pcap packet filtering

If libcoral was compiled with libpcap, these functions can be used to set pcap filter expressions. Pcap filters can be used with any type of interface, not just BPF devices. The filter will be executed when it is most efficient: in the kernel if the interface is a BPF device, or before AAL5 reassembly (if possible) if the interface is an ATM Coral device or file. The packet reading functions will return only packets which match the filter.
int coral_add_pcap_filter(const char *expr)
If expr is not NULL, coral_add_pcap_filter() sets expr as a global pcap filter expression. If a filter expression was already set (either by this function or by coral_config "filter" commands), the old and new expressions are joined as "(old_expr) and (expr)". The expression will be compiled and set on every source that is subsequently opened; it has no effect on sources that are already open.

If expr is NULL, coral_add_pcap_filter() clears any previously set global pcap filter expression.

This function will not work until coral_set_api(CORAL_API_PKT) is called. This function returns 0 if successful, or -1 with errno set if there is an error.

See also the section on -Cfilter in the command usage document.

const char *coral_get_pcap_filter(void)
Returns the text of the global pcap filter expression previously set by coral_add_pcap_filter() and/or by coral_config "filter" commands. Returns NULL if no filter expression has been set.
int coral_pcap_compile(coral_iface_t *iface, struct bpf_program *fp, char *str,
    int optimize, uint32_t netmask);
int coral_pcap_setfilter(coral_iface_t *iface, struct bpf_program *fp);
If you need finer control over pcap filtering than coral_add_pcap_filter() provides, you can use these two functions. These allow you to recompile and reset filters at any time (even on interfaces that are already open), and to assign different filters to different interfaces.

These two functions are the same as pcap_compile() and pcap_setfilter(), respectively, except that they apply to a coral_iface_t instead of a pcap_t. They are used to compile a tcpdump expression to a BPF program and install it onto a Coral interface. Note that *fp must remain in valid memory until iface is closed or a new BPF program is installed on iface.

To avoid confusion when using these functions, you should set the CORAL_OPT_NO_FILTER option before calling the coral_config functions to prevent the user from specifying a useless "filter" command. Alternatively, you could allow the user to use "filter" commands, use coral_get_pcap_filter() to get it so you can combine it with yours, and coral_add_pcap_filter(NULL) to clear the global expression so it won't be applied by coral_open().

These functions require including the pcap header <pcap.h>.

See the pcap and tcpdump documentation for more information.

Packet reading example

static int count_and_print_pkt(coral_iface_t *iface,
    const coral_timestamp_t *timestamp, void *mydata,
    coral_pkt_buffer_t *buffer, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer)
{
    long *countp = mydata;

    ++(*countp);
    if (buffer->caplen == buffer->totlen)  /* complete capture? */
        printf("bytes: %d\n", buffer->caplen);
    else
        printf("bytes: %d (of %d)\n", buffer->caplen, buffer->totlen);
    dump_packet(timestamp, buffer->buf);
}

int main()
{
    long count;
    ...
    count = 0;
    coral_read_pkts(src, NULL, count_and_print_pkt, NULL, NULL, 0, &count);
    printf("received %ld packets.\n", count);
    ...
}

Cell/Block Reading

General Description

The block and cell reading functions may be used only with ATM interfaces that have been started. The cell functions are more general than the block functions. For working with layers 3 and above, the packet reading functions are usually better.

After any of these reading functions are successful, *cellp will point to a single cell (for the cell functions) or array of cells (for the block functions); and if binfop is not NULL, *binfop will point to a block info structure describing the block to which the cell or cells belong. All structures will be in network byte order. (In version 3.0, cells read from FATM devices had ATM headers in little endian order.) binfop may be passed a value of NULL if the block info will not be needed.

If timeout is NULL or omitted, these functions will wait until data are available or an interrupt occurs. But if timeout is not NULL, these functions will also return after the amount of time specified in timeout even if there are no data.

If coral_cell_block_hook is not NULL, the function to which it points will be called when a new block of ATM cells is read by any of the cell reading functions.

The deny protocol rules are applied by the cell reading functions to filter the cells and determine their protocol. They are not applied by the block reading functions. In either case, no protocol information is given; use coral_proto_rule to get that. Note: prior to version 3.4.2, the cell reading functions did not apply the the configuration deny rules.

Calls to the different CoralReef reading functions may not be interleaved on a given set of sources.

A call to any CoralReef reading function on a given set of sources invalidates all data in buffers set by previous calls to any reading functions on the same set of sources.

Return values

(Certain types of errors that were reported as EOF in versions prior 3.5 are now correctly reported as errors.)

Reading Functions

coral_iface_t *coral_read_cell(coral_source_t *src, coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, struct timeval *timeout);
coral_iface_t *coral_read_cell_all(coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, struct timeval *timeout);
coral_read_cell() reads a single cell from the indicated source; coral_read_cell_all() reads from all open sources. If the CORAL_OPT_SORT_TIME option is off, coral_read_cell_all() reads cells in the most efficient order (i.e., block order); but if the CORAL_OPT_SORT_TIME option is on, it will read them in time-sorted order (interleaving cells from blocks of different interfaces). If the CORAL_OPT_SORT_TIME is set, timeout is ignored (it is always treated as NULL).

See the section introduction above for more details and return values.

coral_iface_t *coral_read_cell_i(coral_source_t *src, coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, coral_interval_result_t *int_result,
    struct timeval *interval);
coral_iface_t *coral_read_cell_all_i(coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, coral_interval_result_t *int_result,
    struct timeval *interval);
These functions are like coral_read_cell() and coral_read_cell_all(), except that there is no timeout and they support intervals.

If the value of interval is greater than 0.0, then time sorting is automatically enabled regardless of the setting of the CORAL_OPT_SORT_TIME option, and whenever *interval seconds have passed or EOF is reached, the functions will return non-NULL with *cellp == NULL to indicate that an interval has ended, and the start and end fields of int_result will be filled in with the boundaries of the interval. *binfop is undefined at the end of an interval. int_result->stats is always NULL. When EOF is reached, the final partial interval is returned, and the next call will return NULL.

See the section introduction above for more details and return values.

coral_iface_t *coral_read_block(coral_source_t *src, coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, struct timeval *timeout);
coral_iface_t *coral_read_block_all(coral_blk_info_t **binfop,
    coral_atm_cell_t **cellp, struct timeval *timeout);
The cell reading functions are usually more convenient than these block reading functions.

After a successful read, the number of valid cells in the array pointed to by *cellp is indicated by ntohl((*binfop)->cell_count), the number of bytes (including padding) pointed to by *cellp is indicated by ntohl((*binfop)->blk_size), and the size of a cell is coral_cell_size(iface). The nth cell in the array pointed to by *cellp which was read from interface iface can be found with the expression coral_nth_cell(iface, *cellp, n).

Related Functions

coral_atm_cell_t *coral_nth_cell(const coral_iface_t *iface,
    coral_atm_cell_t *blk, int n)
Returns a pointer to the nth cell in the array of cells pointed to by blk, which was read from iface. (coral_nth_cell() is actually defined as a macro.)
void (*coral_cell_block_hook)(const coral_iface_t *iface, const coral_blk_info_t *binfo)
If coral_cell_block_hook is not NULL, the function to which it points will be called whenever a cell reading function or packet reading function reads a new block of ATM cells. iface and binfo will point to data about the new block. The default value of coral_cell_block_hook is NULL.
int coral_proto_rule(const coral_iface_t *iface, uint32_t subif,
    coral_protocol_t *protop)
This function compares iface and subif (ATM vp:vc) against the proto and deny configuration rules. If they are denied by the rules, coral_proto_rule returns 0. Otherwise, it sets *protop to the protocol identifier according to the rules, and returns 1. Cells that would be denied by the rules are never returned by the cell API, but this function is still needed to find the protocol of the PDU to which a cell belongs or to test for denial of a cell returned by the block API.

If there is no matching proto configuration rule for subif, and there is no default protocol for iface, the protocol for 0:0 through 0:15 defaults to CORAL_PROTO_UNKNOWN, the protocol for 0:16 defaults to CORAL_DLT_ILMI, and the protocol for all other virtual channels defaults to CORAL_DLT_ATM_RFC1483.

Although coral_read_pkt puts IEEE 802.1Q VLAN IDs in the pkt_result->subif field, protocol rules should not be applied to VLAN IDs.

int coral_cell_to_pkt(const coral_iface_t *iface, coral_atm_cell_t *cell,
    coral_pkt_buffer_t *pkt)
Cell is a pointer to the first cell of an AAL5 PDU (in network byte order). coral_cell_to_pkt fills in the object pointed to by pkt with information from cell and iface, for use with functions that expect a coral_pkt_buffer_t argument. Iface and the cell's vp:vc are used to determine the protocol of the data according to the configuration proto rules. If iface is NULL, pkt->protocol will be set to CORAL_PROTO_UNKNOWN.

The return value is 0 if iface and the cell's vp:vc match a configuration deny rule, otherwise 1.

Information

These functions provide information about CoralReef, cells, interfaces, and sources.
const char *coral_file_version(const coral_source_t *src);
Returns a pointer to a static buffer containing a string describing a file format version. If src corresponds to a tracefile, the string describes the file format of the tracefile; if src is NULL, the string describes the current file format (i.e., the highest format version that this version of libcoral can read, and the format that would be written by coral_write() in this version of libcoral).
double coral_read_clock_double(const coral_iface_t *iface, const coral_timestamp_t *t);
void coral_read_clock_sec_nsec(const coral_iface_t *iface, const coral_timestamp_t *t,
	time_t *sec, long *nsec);
void CORAL_TIMESTAMP_TO_TIMEVAL(const coral_iface_t *iface, const coral_timestamp_t *t,
	struct timeval *tv);
void CORAL_TIMESTAMP_TO_TIMESPEC(const coral_iface_t *iface, const coral_timestamp_t *t,
	struct timespec *ts);
These functions parse the timestamp t, which belongs to a coral_cell_t or coral_pkt_buffer_t read from interface iface, and convert it to a more useful format.

If the CORAL_OPT_NORMALIZE_TIME option is set, the result will be measured from the unix epoch; otherwise, the result will have some interface-dependant epoch. Normalization may introduce some error in the precision; this error will be the same for all timestamps from the same interface, but may be different for different interfaces.

These functions automatically correct the case in which the FORE card doesn't increment the firmware clock because it misses a hardware clock wrap, unless the CORAL_OPT_FATM_RAW_TIME option is set.

coral_read_clock_double() returns the time as floating point number of seconds. Note that some precision may be lost by the conversion to double.

coral_read_clock_sec_nsec(), CORAL_TIMESTAMP_TO_TIMEVAL(), and CORAL_TIMESTAMP_TO_TIMESPEC() splits the time into two integers, seconds and residual fractions of a second, and writes them into *sec and *nsec, *tv, or *ts, respectively.

double coral_cell_time_double(const coral_iface_t *iface, coral_atm_cell_t *cell);
Equivalent to coral_read_clock_double(iface, coral_cell_time(iface, cell)).
coral_iface_t *coral_next_interface(const coral_iface_t *iface);
coral_source_t *coral_next_source(const coral_source_t *src);
If iface/src is NULL, these functions return a pointer to the first CoralReef interface/source; otherwise, they return a pointer to the interface/source following iface/src. They return NULL if there is no next interface/source. The order in which interfaces/sources are returned is not necessarily the order in which they were opened. These functions are used to step through all interfaces/sources, for example:
    coral_source_t *src = NULL;
    while ((src = coral_next_source(src))) {
        coral_dump(src);
    }
coral_iface_t *coral_next_src_iface(const coral_source_t *src,
    const coral_iface_t *iface);
Like coral_next_interface(), except it only returns interfaces of src.
const char *coral_source_get_filename(const coral_source_t *src);
Returns the name of the file or network interface of source src, without a coral type prefix. Returns NULL if src is bad.
const char *coral_source_get_name(const coral_source_t *src);
Returns the name of the source src, including a coral type prefix, if any. Returns NULL if src is bad.
const char *coral_source_get_comment(const coral_source_t *src);
Returns a pointer to the comment string from the file header of source src. Returns NULL if src is bad or there is no comment.
int coral_get_source_count(void);
Returns the number of sources.
coral_source_t *coral_interface_get_src(const coral_iface_t *iface);
Returns a pointer to the source to which interface iface belongs, or NULL if iface is bad.
int coral_interface_get_type(const coral_iface_t *iface);
Return the original (hardware) type of interface iface, or return CORAL_TYPE_NONE if iface is invalid or its type is unknown.
CORAL_TYPE_FATM
FORE ATM adaptor device
CORAL_TYPE_POINT
Apptel POINT device
CORAL_TYPE_DAG
Waikato DAG device
CORAL_TYPE_PCAPLIVE
pcap interface
int coral_source_get_type(const coral_source_t *src);
Return the type of source src, or CORAL_TYPE_NONE if src is invalid or its type is unknown. For live sources, the type will be one of the types listed in the description of coral_interface_get_type(); for file sources, the type will be one of the following:
CORAL_TYPE_FILE
CoralReef trace file
CORAL_TYPE_PCAP
pcap (tcpdump) trace file
CORAL_TYPE_DAGFILE
dagtools trace file
CORAL_TYPE_TSH
NLANR Time Sequenced Header trace file
int coral_interface_get_datalink(const coral_iface_t *iface);
Return the data link layer type of interface iface, or CORAL_PROTO_UNKNOWN if the protocol is unknown, or -1 if iface is bad. The data link layer type is one of the CORAL_DLT_* (layer 2) constants defined in the Command Usage document.
int coral_interface_get_physical(const coral_iface_t *iface);
Return the physical layer type of interface iface, or CORAL_PROTO_UNKNOWN if the protocol is unknown, or -1 if iface is bad. The physical layer type is one of the CORAL_PHY_* (layer 1) constants defined in the Command Usage document.
int coral_interface_get_bandwidth(const coral_iface_t *iface);
Return the bandwidth (in kilobits per second) of interface iface, or 0 if the bandwidth is unknown, or -1 if iface is bad.
int coral_source_get_number(const coral_source_t *src);
int coral_interface_get_number(const coral_iface_t *iface);
Return a non-negative integer identifier of source src or interface iface, or return -1 if src or iface is bad. The identifier returned is not really useful except as a label. To print an interface number, see coral_fmt_if_subif().
const struct timeval *coral_interface_get_capture_tv(const coral_iface_t *iface);
Returns a pointer to a structure containing the time (relative to the unix epoch) of the start of the capture on interface iface, or NULL if there was an error. The structure will contain 0,0 if the start time is unknown. Note: the microsecond component will always be 0 in traces in the old NLANR and MCI formats and traces made with CoralReef versions prior to 3.2.2 (format version 9).
time_t coral_interface_get_capturetime(const coral_iface_t *iface);
Returns the integer component of the value that would be returned by coral_interface_get_capture_tv(iface).
const char *coral_proto_abbr(coral_protocol_t protocol);
const char *coral_proto_desc(coral_protocol_t protocol);
const char *coral_proto_str(coral_protocol_t protocol);
Protocol is a CORAL_prefix_name constant (listed in the Command Usage document) indentifying a communication protocol. These functions return a pointer to a string describing protocol:
coral_protocol_t coral_proto_id(const char *name);
Returns a protocol id constant (listed in the Command Usage document) corresponding to name, which may be a short abbreviation or a long description as returned by coral_proto_{abbr,desc,str}().
int coral_proto_layer(coral_protocol_t protocol);
Returns the layer number of protocol.

vpvc macros

Parameters:
vpvc
a variable containing a combined VPI and VCI.
vp
a VPI (virtual path indicator)
vc
a VCI (virtual channel indicator)

Macros:

get_vpvc_vp(vpvc)
returns the VPI of vpvc.
get_vpvc_vc(vpvc)
returns the VCI of vpvc.
set_vpvc_vp(vpvc, vp)
sets the VPI of vpvc.
set_vpvc_vc(vpvc, vc)
sets the VCI of vpvc.
vp_vc_to_vpvc(vp, vc)
returns the combined value of vp and vc.

Trace Writing

The writing API allows a programmer to copy data from a CoralReef source to a CoralReef-format trace file. The source is typically a OCx device (for doing data capture), but may also be another trace file (useful for encoding, or converting from another format).
coral_writer_t *coral_write_open(const char *name);
Open file name for writing a trace file in CoralReef format. If the name ends in ".gz" or the "gzip" configuration option was given, and CoralReef was compiled with libz, the file will be gzipped. (coral_set_api() must be called with the CORAL_API_WRITE bit to enable the "gzip" configuration option.) If the name is "-", data will be written to stdout. Returns a pointer to a coral writer for success, NULL for failure. The reccommended suffix for CoralReef trace files is ".crl", and for encoded CoralReef trace files is ".enc.crl".

To ensure that all data from all sources are read, you must call coral_stop() on any sources which have not reached EOF. Then, to ensure that all data from all sources are written, you must call coral_write_close() on the writer, before calling coral_close() on the sources.

coral_writer_t *coral_write_fdopen(int fd);
Like coral_write_open, except it uses the already-open file descriptor fd instead of a filename.

Mixing CoralReef operations with other operations on descriptor fd may have unpredictable effects.

int coral_write_set_comment(coral_writer_t *writer, const char *comment);
int coral_write_set_encoding(coral_writer_t *writer, const char *encoding);
These functions set the comment or encoding strings that will be written into the file header of writer. The string parameters are null-terminated strings; comment may be up to 255 characters, encoding may be up to 31 characters. These functions return 0 for success, -1 for failure.
int coral_write_init_all(coral_writer_t *writer);
int coral_write_init_source(coral_writer_t *writer, coral_source_t *src);
Prepare to write data from the indicated sources to writer. Returns 0 for success, -1 for failure.
int coral_write_init_interface(coral_writer_t *writer, coral_iface_t *iface);
Prepare to write data from a single interface iface to tracefile writer. Returns 0 for success, -1 for failure.
int coral_write_cells(coral_writer_t *writer, const coral_iface_t *iface,
    const coral_atm_cell_t *cell, int count);
Write an array of count cells pointed to by cell to writer. iface indicates which interface the cells were read from (as returned by a CoralReef reading function. Returns 0 for success, -1 for failure.
int coral_write_block(coral_writer_t *writer, const coral_iface_t *iface,
    const coral_blk_info_t *binfo, const coral_atm_cell_t *blk);
Write a block of cells pointed to by blk with block info binfo to writer. The structure pointed to by binfo must be in network byte order. iface indicates which interface the cells were read from (as returned by a CoralReef reading function). This function is more efficient than coral_write_cells(). Returns 0 for success, -1 for failure.
int coral_write_close(coral_writer_t *writer);
Close the coral trace indicated by writer. Returns 0 for success, -1 for failure. To ensure that all data from all sources are read, you must call coral_stop() on any sources which have not reached EOF. To ensure that all data from all sources are written, you must call coral_write_close() on the writer, before calling coral_close() on the sources.

Trace writing example

int main(int argc, char *argv[]) {
    coral_writer_t *writer;
    coral_iface_t *iface;
    coral_atm_cell_t *blk;
    coral_blk_info_t *binfo;

    coral_set_duration(60);
    if (coral_config_arguments(argc, argv) < 0)
	exit(2);
    writer = coral_write_open("out.crl");
    if (!writer)
        exit(3);
    if (coral_write_init_all(writer) < 0)
        exit(4);
    if (coral_start_all() < 0)
        exit(5);

    while ((iface = coral_read_block_all(&binfo, &blk, NULL))) {
        if (coral_write_block(writer, iface, binfo, blk) < 0)
            exit(6);
    }

    coral_stop_all();
    coral_write_close(writer);
    coral_close_all();
}

Pcap (tcpdump) Conversion

These functions convert CoralReef structures to pcap structures, so they may be used with pcap and BPF functions. To use these functions, the pcap header must be included:
	#include <pcap.h>
pcap_t *coral_iface_to_pcapp(coral_iface_t *iface);
pcap_t *coral_iface_to_pcapp_raw(coral_iface_t *iface);
Returns a pointer to a pcap_t containing information copied from *iface, or returns NULL if there is an error. If coral_iface_to_pcapp_raw is called, or coral_iface_to_pcapp is called but iface uses a data link layer protocol not supported by pcap, the created pcap_t structure will be set to DLT_RAW (raw IP), and coral_pkt_to_pcap() calls on the pcap_t will strip encapsulation from IP packets and discard non-IP packets.

The caller must not pcap_close() or free() the resulting pcap_t; libcoral will do this automatically when iface is closed. (Prior to version 3.4, it was the caller's responsibility to free the pcap_t.)

int coral_iface_to_pcap(const coral_iface_t *iface, pcap_t *pcap);
Obsolete. See coral_iface_to_pcapp().
int coral_pkt_to_pcap(coral_iface_t *iface, const coral_timestamp_t *timestamp,
    const coral_pkt_buffer_t *pkt, pcap_t *pcap, struct pcap_pkthdr *hdr);
Parameters:
iface
A pointer to a coral interface from which pkt was read
timestamp
A pointer to the timestamp of pkt
pkt
A pointer to a packet that was read from iface
pcap
A pointer to a pcap structure returned by coral_iface_to_pcapp() or coral_iface_to_pcapp_raw()
hdr
A pointer to a pcap_pkthdr which will be filled in by the call
This function fills in *hdr with information from *iface, *timestamp, and *pkt. If *timestamp is not NULL, its value will be normalized to the unix epoch and copied to hdr->ts; otherwise, hdr->ts will be set to zero. (The timestamp was not normalized in versions before 3.2.2.)

The linktype of pcap must be either DLT_RAW or compatible with the protocol of iface. The former condition is true if pcap was created by calling coral_iface_to_pcapp_raw(). The latter condition is true if pcap was created by calling coral_iface_to_pcapp() on iface or another coral interface with the same protocol as iface.

If the linktype of pcap is compatible with the protocol of iface, this function simply copies and converts the information into hdr, and returns 0.

If the linktype of pcap is DLT_RAW, this function will strip off the encapsulation to find an IP packet. If there is no IP packet, this function returns -1. If there is an IP packet, this function returns the offset of that IP packet within pkt->buf, and fills in the rest of hdr with information about the IP packet, not the original packet.

This function returns -1 to indicate an error or that the packet could not be converted to pcap form.

int coral_write_pkt_to_pcap(coral_iface_t *iface, const coral_timestamp_t *timestamp,
    const coral_pkt_buffer_t *pkt, pcap_t *pcap, struct pcap_dumper_t *pcap_dumper);
This function calls coral_pkt_to_pcap() to convert the CoralReef packet pkt to a pcap packet, and writes it to pcap_dumper with pcap_dump().

Example

This example reads packets from a CoralReef interface and writes them to a tcpdump file.
	pcap_t *pcap;
	struct pcap_pkthdr pcap_hdr;
	int offset;

	/* ... */

	pcap = coral_iface_to_pcapp(iface);
	if (!pcap)
	    /* handle error */;
	pcap_dumper = pcap_dump_open(pcap, filename);

	/* ... */

	iface = coral_read_pkt(&pkt_result, &interval_result);
	if (!iface)
	    /* handle error */;
	offset = coral_pkt_to_pcap(iface, pkt_result.timestamp,
	    pkt_result.packet, &pcap_hdr);
	if (offset < 0)
	    /* handle error */;
	pcap_dump(pcap_dumper, &pcap_hdr, pkt_result.packet->buf + offset);
Note: in the example above, it is possible to open a pcap dumper for coral interface A, and then dump packets to it that were read from coral interface B. This is ok only if interfaces A and B have the same data link type, bandwidth, and other properties; otherwise, coral_pkt_to_pcap() will return an error without writing the incompatible packet.

Other

char *coral_filename(const char *str, char *dst, size_t len);
Copies str to dst, with any leading "~name/" replaced with the home directory of user name, and any leading "~/" replaced with the home directory of the user who owns the process. At most len - 1 characters will be written into dst. (A typical value for len is PATH_MAX, defined in <limits.h>.) If dst is NULL, coral_filename() will malloc len bytes for it before writing to it. It is the caller's responsibility to free the allocated memory. The return value is a pointer to the buffer containing the expanded filename, or NULL if coral_filename() could not allocate the required memory.
#include <sys/types.h>
#include <sys/socket.h>
int coral_inet_pton(int af, const char *src, void *dst);
Same as inet_pton(), for hosts that don't have inet_pton() or inet_aton(). (Note that inet_addr() is unable to distinguish between the IPv4 address 255.255.255.255 and an error.) Converts an address string in src to an internal form in dst according to the address family af. Valid values for af are AF_INET and AF_INET6.
int coral_puts(const char *str);
Like the standard C function puts(str), except that it prints to the CoralReef errfile instead of stdout, and it is guaranteed to not modify errno.
int coral_printf(const char *fmt, ...);
Like printf(fmt, ...), except that it prints to the CoralReef errfile instead of stdout, and it is guaranteed to not modify errno.
void coral_diag(level, (fmt, ...))
Like coral_printf(fmt, ...), except that nothing will be printed if level > verbosity. Returns void.
int coral_sendblk(coral_source_t *src, int ndesc);
Incomplete.
void coral_fprint_data(FILE *file, int indent, const u_char *data, size_t len);
void coral_print_data(int indent, const u_char *data, size_t len);
coral_print_data prints len bytes from data to stdout in a easily readable format: 16 hex values per line, with each line indented indent spaces. coral_fprint_data is like coral_print_data, except it prints to file instead of stdout.
void coral_fprint_cell(FILE *file, int indent, const coral_iface_t *iface,
    const coral_atm_cell_t *cell);
void coral_print_cell(int indent, const coral_iface_t *iface,
    const coral_atm_cell_t *cell);
coral_print_cell prints cell (which was read from iface) to stdout in an easily readable format, with the timestamp in seconds, the ATM header expanded by fields, and the payload in hex, with each line indented indent spaces. This format is used by the application crl_print. coral_fprint_cell is like coral_print_cell, except it prints to file.
void coral_fmprint_pkt(FILE *file, coral_iface_t *iface,
    const coral_timestamp_t *timestamp, int minlayer, int maxlayer,
    coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
coral_fmprint_pkt prints packet and optionally header and trailer (which were read from iface) to file in an easily readable format, with the timestamp in seconds. Protocol layers less than minlayer will be skipped; layers between minlayer and maxlayer will be expanded by fields in an easily readable format; layers greater than maxlayer or not understood by libcoral will be printed in hex. This format is used by the application crl_print_pkt.
void coral_fprint_pkt(FILE *file, coral_iface_t *iface,
    const coral_timestamp_t *timestamp, int maxlayer,
    coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
coral_fprint_pkt(iface, timestamp, maxlayer, packet, header, trailer) is equivalent to coral_fmprint_pkt(iface, timestamp, 1, maxlayer, packet, header, trailer).
void coral_mprint_pkt(coral_iface_t *iface, const coral_timestamp_t *timestamp,
    void *layerp, coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
void coral_print_pkt(coral_iface_t *iface, const coral_timestamp_t *timestamp,
    void *layerp, coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
These functions are like coral_fmprint_pkt(), except they print to stdout, and the layers are specified differently. For coral_mprint_pkt(), layerp is a pointer to an array of two integers containing minlayer and maxlayer. For coral_print_pkt(), layerp is a pointer to a single integer containing maxlayer; minlayer defaults to 1. The odd syntax for specifying layers makes these functions suitable for use as a coral_pkt_handler for coral_read_pkts().
int coral_fmt_if_subif(char *buf, coral_iface_t *iface, uint32_t subif);
coral_if_fmt_subif prints a formatted representation of iface id and subif into buf. The size of buf should be at least CORAL_FMT_IF_SUBIF_LEN. If the data link type of iface does not have subinterfaces, the format is just the interface number (coral_interface_get_number); if it does, the format is "if[subif]", where subif is formated as by coral_fmt_subif. This function returns the length of the formatted string.
int coral_fmt_subif(char *buf, coral_iface_t *iface, uint32_t subif);
coral_fmt_subif prints a formatted representation of subif into buf. The size of buf should be at least CORAL_FMT_SUBIF_LEN. The format depends on the data link type of iface: This function returns the length of the formatted string.
void coral_dump(const coral_source_t *src);
void coral_dump_all(void);
Prints information about the indicated sources to the CoralReef errfile, like the application crl_info.
void coral_stats(const coral_source_t *src);
void coral_stats_all(void);
Prints statistics about the indicated sources to the CoralReef errfile.
uint32_t coral_in_cksum_add(uint32_t psum, const void *data, int len);
uint16_t coral_in_cksum_result(uint32_t psum);
Calculates the internet checksum of the string in data. Usage:
  1. initialize psum to 0
  2. call psum = coral_in_cksum_add(psum, data, len) for each segment of buffer, where data is a pointer to the segment and len is the length of the segment
  3. call coral_in_cksum_result(psum) to get result.
Segments must be short-aligned. Entire message must have length less than 32768.

Types

The definitions here are not necessarily complete; actual structures may contain undocumented fields that should not be accessed by the programmer.
ANSI/ISO C fixed width integer types
int8_t, int16_t, int32_t, int64_t,
uint8_t, uint16_t, uint32_t, uint64_t
If these are not alrelady defined on your platform, <libcoral.h> will define them.

coral_source_t - Coral Source
An opaque structure representing a source of network traffic: either a tracefile or a real network device. See the Introduction.

coral_iface_t - Coral Interface
An opaque structure representing a single network device within a source (since a tracefile may contain data from multiple devices). See the Introduction.

coral_writer_t - Coral Writer
An opaque structure representing a file to which the coral_write functions will write.

coral_timestamp_t - Coral Timestamp
An opaque interface-specific timestamp format that should be accessed through the coral_read_clock functions.

coral_protocol_t - Coral Protocol
A protocol identifier. See the protocols section of the Command Usage document.

coral_blk_info_t - ATM block info
The coral_blk_info_t structure defined in <libcoral.h> is used by many functions. All members are in network byte order. It has at least these members:
    u_int               interface;      /* which card this came from, if 
                                         * applicable */
    u_int               blk_size;       /* number of bytes in block */
    u_int               cell_count;     /* number of valid cells in this blk */
    u_int               cells_lost;     /* number of cells lost during block */
    u_int               unknown_vpi_vci;/* cells dropped because vpi/vci 
                                         * unknown */
    struct timespec     tbegin;         /* time of block start */
    struct timespec     tend;           /* time of block end */
Note that the interface field may not correspond to the number of the iface pointer returned by the CoralReef reading functions.

atm_hdr - ATM header
The atm_hdr.h structure will only be available if BYTE_ORDER or WORDS_BIGENDIAN is defined when <libcoral.h> is included. (BYTE_ORDER is defined in <sys/param.h> on some platforms, and WORDS_BIGENDIAN can be defined by a GNU configure script.) The programmer must ensure that atm_hdr.ui is in host byte order before accessing fields of atm_hdr.h.
union atm_hdr {
    struct {
        uint32_t gfc        : 4;  /* generic flow control */
        uint32_t vpvc       : 24; /* virtual path + circuit indicators */
        uint32_t oam_rm     : 1;  /* PTI: OAM/RM indicator (ie, not user data) */
        uint32_t congestion : 1;  /* PTI: we don't use this */
        uint32_t sdu_type   : 1;  /* PTI: in AAL5, this marks end of SAR-SDU */
        uint32_t clp        : 1;  /* cell loss priority */
    } h;
    uint32_t ui;
};
coral_atm_cell_t - ATM cell
As of version 3.3, the ATM cell record structure is not directly accessible; coral_atm_cell_t is just void. All access to the fields of a cell record must be done with the accessor functions below. This is so libcoral can support different record layouts used by different hardware, firmware, and drivers.

Any of the accessors that return a pointer may return NULL if the field is not available because of hardware, firmware, or driver options.

const coral_timestamp_t *coral_cell_time(iface, cell);
Returns a pointer to the timestamp of cell, in an interface-specific format that should be accessed through the coral_read_clock functions.
const union atm_hdr *coral_cell_header(iface, cell);
Returns a pointer to the first 4 bytes (containing VPI, VCI, PTI, CLP) of the ATM header of cell (in network byte order). The result will be NULL if iface is not an ATM interface.
const char *coral_cell_hec(iface, cell);
Returns a pointer to the Header Error Control byte of the ATM header of cell.
const char *coral_cell_payload(iface, cell);
Returns a pointer to the 48-byte payload of cell.
size_t coral_cell_size(iface);
Returns the size of the cell structure used by iface.
Iface is a (coral_iface_t *) pointing to the interface from which cell was read. Cell is a (coral_atm_cell_t *) pointing to the cell record from which the field will be read. Any of the accessor functions that return a pointer may return NULL if the corresponding field is not present in the cell structure for the given interface.

The old version of the structure is documented here for reference only.

typedef struct {
    coral_timestamp_t t;	/* timestamp, in card-specific format */
    union atm_hdr cu;		/* ATM header (without HEC) */
    union {
	char payload[48];
	short payload_shorts[24];
	u_int payload_i[12];
    } p;			/* ATM cell payload == SAR-PDU */
} coral_atm_cell_t;
aal5_trailer_t - ATM AAL5 trailer
typedef struct {
    uint8_t	cpcs_uu;	/* CPCS user-to-user inidication */
    uint8_t	cpi;		/* common part indicator */
    uint16_t	length;		/* length of CPCS PDU payload */
    uint32_t	crc;		/* cyclic redundancy check of CPCS PDU */
} aal5_trailer_t;

coral_llcsnap_t - LLC/SNAP header (IEEE 802.2 and rfc1042)
typedef struct {
    uint8_t	llc_dsap;
    uint8_t	llc_ssap;
    uint8_t	llc_cntl;
    uint8_t	snap_org[3];
    uint16_t	snap_type;
} coral_llcsnap_t;

coral_pkt_buffer_t - Buffer structure for packet API
typedef struct {
    int caplen;			/* length of data actually captured in buf */
    int totlen;			/* total length of pkt (negative if unknown) */
    const char *buf;		/* data (aligned to a multiple of 4 bytes) */
    coral_protocol_t protocol;	/* protocol */
} coral_pkt_buffer_t;

coral_pkt_stats_t - Statistics for packet API
typedef struct {
    uint64_t l2_recv;           /* Layer 2 PDUs received */
    uint64_t l2_drop;           /* Layer 2 PDUs dropped */
    uint64_t pkts_recv;         /* packets received */
    uint64_t pkts_drop;         /* packets dropped */
    uint64_t truncated;         /* packets truncated by insufficient capture */
    uint64_t driver_corrupt;    /* cell looks bad from the capture device */
    uint64_t too_many_vpvc;     /* too many simultaneous vpvc pairs */
    uint64_t buffer_overflow;   /* AAL5 cell stream > MAX_PACKET_SIZE */
    uint64_t aal5_trailer;      /* AAL5 trailer had bad length */
    uint64_t ok_packet;

} coral_pkt_stats_t;
The l2_recv and l2_drop fields count layer 2 PDUs (e.g., ATM cells), and may not be totally accurate. On interfaces that operate on blocks (i.e., POINT, FORE ATM, and DAG), the layer 2 PDUs reported are those belonging to every block that started within the interval. If there are many blocks per interval the error should be small, but if traffic is low the error is more significant. If you require more accurate per-block data, use coral_cell_block_hook.

coral_pkt_result_t - Packet results for packet API
typedef struct {
    const coral_timestamp_t *timestamp; /* time packet was read */
    coral_pkt_buffer_t *packet;         /* link or sub-network layer packet */
    coral_pkt_buffer_t *header;         /* link layer header (eg, ATM) */
    coral_pkt_buffer_t *trailer;        /* link layer trailer (eg, AAL5) */
    uint32_t subiface;       /* sub-interface id (ATM VPVC or VLAN ID) */
} coral_pkt_result_t;
The subiface field can be formatted with coral_fmt_subif().

coral_interval_result_t - Interval results for packet API
typedef struct {
    struct timeval begin;               /* beginning of interval */
    struct timeval end;                 /* end of interval */
    coral_pkt_stats_t *stats;           /* packet statistics for interval */
} coral_interval_result_t;