libcoral - a C API for CoralReef

Introduction

Libcoral provides a C API for reading OCx devices and several different trace file formats, and for writing trace files. A simple but realistic example of its use can be found in apps/skel.c.

Libcoral operates on "sources". A libcoral source can be created from any of these filesystem entries:

A device source has one interface. But a trace file may have been created by monitoring multiple devices, so it may contain multiple interfaces.

The basic sequence of events for using libcoral to read a CoralReef source is:

  1. Configure libcoral and one or more sources
  2. Open sources
  3. Start sources
  4. Loop: read single cells or blocks of cells and analyze them
  5. Stop sources
  6. 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>
CoralReef programs should link with -lcoral. Also, if libcoral was compiled with pcap support, CoralReef programs should link with -lpcap.

The API

User-level Configuration

The following functions read coral commands from the command line or config files. The coral commands are described here. These functions should only be called before coral_open() or coral_open_all().
int coral_config_arguments(int argc, char *argv[]);
Processes command line arguments containing "-C" options and filename arguments. If a "-C 'config filename'" option was given, this function will also process that config file. A CoralReef source is created from each filename argument. If an option syntax error is encountered, this function prints a usage message. If other arguments are desired, use coral_config_options() instead; if other options are desired, use coral_config_command(). 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.

int coral_config_options(int argc, char *argv[], const char *argmsg);
Processes "-C" options on command line. If a "-C 'config filename'" option was given, this function will also process that config file. 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], argmsg). If argmsg is NULL, this function assumes that no arguments other than coral options are allowed, and returns -1 if other arguments are found. If argmsg is not NULL, other arguments (but not other options) are allowed. If other options are desired, use coral_config_command() instead. 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.

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, followed by descriptions of the CoralReef commands. If argmsg is not NULL, it is appended to the syntax line. Some example values for argmsg:
NULL
for an application that takes CoralReef options and no arguments
"[<argument>]"
for an application that takes CoralReef options and an optional argument
"[-b] [-f <string>]"
for an application that takes -b, -f, and CoralReef options
"[-b] [-f <string>] [<argument>]"
for an application that takes -b, -f, and CoralReef options, and an optional argument

Examples

If only CoralReef options and filename arguments are needed, this simple code will do:
    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, bflag = 0;
    char *string = NULL;
    extern char *optarg;
    extern int optind;

    while ((opt = getopt(argc, argv, "C:bf:")) != -1) {
        switch (opt) {
        case 'C':
            if (coral_config_command(optarg) < 0)
                exit(-1);
            break;
        case 'b':
            bflag = 1;
            break;
        case 'f':
            string = optarg;
            break;
        default:
            coral_usage(argv[0], "[-b] [-f <string>]");
            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:
    Usage: app [-C <coral_command>]... [-b] [-f <string>]

Programmer-level Configuration

The following functions provide a way for the programmer to operate on the same configuration values as the coral_config user-level configuration functions. 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 usage message. If the integer configuration values are set to a negative value, they will not be displayed in the usage message. The coral_set functions can 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_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 temporal order. This option may only be used on file sources, not device sources.
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. This can be used to improve performance if cell/packet timestamps will not be needed.
CORAL_OPT_NORMALIZE_TIME (default: off)
Make the result of the coral_read_clock relative to the unix epoch (1970-01-01 00:00:00 Z); 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 offsets. 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());
pcap
the unix epoch (of the CPU used to do the capture)
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; .crl traces made with CoralReef prior to 3.2.1 contain capture time only to the nearest second.
int coral_set_iomode(int off, int on, int first, int fixed);
These functions set the default I/O mode of all subsequently defined sources. Their arguments 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. This is ignored if the CORAL_RX_USER_ALL flag is enabled. For ATM interfaces, first will be rounded up to a multiple of ATM cell payload size. (In versions prior to 3.2, first was interpreted as cells for 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:

CORAL_TX
allow writing
CORAL_RX
allow receiving
CORAL_RX_IDLE
read all cells, including ATM idle cells
CORAL_RX_OAM
read oam/rm cells
CORAL_RX_LAST
read last cell of each packet
CORAL_RX_USER_ALL
read all user data cells of each packet (overrides first)
CORAL_RX_ECHO
retransmit received cells (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=1). 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.

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 cells in the trace will still be read. In a future release, the read functions will filter trace files according to the I/O mode (or generate an error if that is not possible).

On point cards, coralreef supports CORAL_RX, CORAL_RX_IDLE, CORAL_RX_OAM, CORAL_RX_LAST, CORAL_RX_USER_ALL; and a first value of 0, 1, 2, or 3. Echoing is is always enabled, no matter how CORAL_RX_ECHO is set.

On fatm cards, coralreef supports CORAL_TX, CORAL_RX, CORAL_RX_LAST, CORAL_RX_USER_ALL, CORAL_RX_ECHO; and a first value of 0, 1, 2, or 3.

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 (e.g., by coral_set_errfilename(), but not by coral_set_errfile()). If file or filename is NULL, stderr 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_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_writer_set_comment().
int coral_set_duration(long duration);
long coral_get_duration(void);
int coral_set_interval(long interval);
long coral_get_interval(void);
Set or get a duration or interval value. The duration and interval values do not have any special meaning to libcoral; these functions just provide a convenient way to set a default value, and then read a configured value from the command line or config file. Generally, you should set the default value before calling any of the coral_config functions, and get the value after. This way, the option and its default value will appear in the coral_usage() message.

If the interval value is greater than 0, it will automatically be used by the cell reading functions. You may use the interval value with packet reading functions by passing the result of coral_get_interval() in as a parameter.

Typically, you should use the duration value if you want to set the length of time that the application will run; and use the interval value if you want to do something periodically during the application run (e.g., by passing it as the interval parameter to coral_read_pkt_init() or coral_read_cell_i()).

Source Configuration

These functions define and configure sources. They may only be called before opening sources.
coral_source_t *coral_new_source(const char *filename);
Create a new coral sources from filename. Tye types of files allowed are described in the introduction. Returns source pointer if successful, or NULL for failure. This function is useful for opening a source directly from the program (instead of through command line and config file with the coral_config functions).
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 sources. The off, on, and first arguments are identical to those of coral_set_iomode(). These functions return 0 for success, -1 for failure.
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

Interfaces must be opened and started before they can be read, and should be stopped and closed when they are no longer needed.
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. Returns the number of interfaces opened if successful, or -1 for failure. 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. These functions currently have no effect on tracefile sources, but should be called anyway for consistency and future compatibility.
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. There may be data buffered in the source, which can still be read until the reading function returns an EOF indication. These functions have no effect on trace file sources. These functions are not safe to call asynchronously.

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 data link level packets (i.e., ATM or pcap type interfaces). All time is measured against packet timestamps, so it works even for trace files that aren't in real time.

Single packet reading

int coral_read_pkt_init(coral_source_t *src, coral_iface_t *iface,
    int 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. Packets can be read from multiple OCx sources, or a single pcap source, but not from multiple pcap sources or a mixture of pcap and OCx sources. If iface belongs to a source with multiple interfaces, data from the other interfaces 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 number of seconds coral_read_pkt() will wait between returning statistical information (measured against packet timestamps). 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().

pkt_result and interval_result are pointers to structures 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:

pkt_result->packet == NULL && interval_result->stats == NULL
An interval has begun at time interval_result->begin. (interval_result->end is not valid.)
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); and pkt_result->trailer will point to a coral_pkt_buffer_t containing the AAL5 trailer (in network byte order), if available. On other types of interfaces, pkt_result->header and pkt_result->trailer will be NULL.
pkt_result->packet == NULL && interval_result->stats != NULL
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 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 interval. The interval includes all packets in each internal buffer for which the first packet of the internal buffer falls within interval seconds of the beginning of the interval. In version 3.1, internal buffering might have made an actual interval quite a bit longer than interval if there was not much traffic on the monitored link; this is no longer true in version 3.2.

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; if there is no matching proto configuration rule, the protocol defaults to CORAL_DLT_ATM_RFC1483.

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

For EOF or a stopped device, coral_read_pkt() returns NULL with errno == 0. For error, coral_read_pkt() returns NULL with errno set to indicate the error.

Callback loop packet reading

int coral_read_pkts(coral_source_t *src, coral_iface_t *iface,
		pkt_handler pkthandler, 
		pre_interval_handler preinthandler, 
		post_interval_handler postinthandler,
		long interval,
		void *userdata);
Reads packets from one or more interfaces. src and iface are interpreted as in coral_read_pkt_init(). coral_read_pkts() repeatedly reads link level packets until coral_pkt_done != 0, or (if input is a trace file) end of file is reached.

pkthandler is a pointer to a function that will be called for each packet received. Normally, even truncated packets are handled, but only complete packets will be handled if the CORAL_OPT_PARTIAL_PKT option is disabled (but truncated packets are always counted by the truncated field of coral_pkt_stats_t).

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. The beginning of an interval is always aligned to a multiple of interval. The interval includes all packets in each internal buffer for which the first packet of the internal buffer falls within interval seconds of the beginning of the interval. Because of internal buffering, a interval may actually be quite a bit longer than interval if there is not much traffic on the monitored link. preinthandler and postinthandler are not called if they are NULL or if interval <= 0.

userdata 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.

typedef void (*pkt_handler)(coral_iface_t *iface, coral_timestamp_t *timestamp,
    void *userdata, coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
pkt_handler is 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).
userdata
the userdata 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 packet's link level header, if the link level uses headers; otherwise, NULL. Currently, this is only used for the ATM header of the last received cell; 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 packet's link level trailer, if the link level uses trailers and the packet was not truncated; otherwise, NULL. Currently, this is only used for the ATM AAL5 trailer.
typedef int (*pre_interval_handler)(coral_iface_t *iface,
	struct timeval *begin, void *userdata);
typedef int (*post_interval_handler)(coral_iface_t *iface,
	struct timeval *begin, void *userdata, coral_pkt_stats_t *stats);
pre_interval_handler and post_interval_handler are called before and after (respectively) each interval of coral_read_pkts(). Parameters:
iface
the interface being read.
begin
the beginning of the interval.
userdata
the userdata parameter that was passed to coral_read_pkts()
stats
a pointer to a structure containing statistics about the interval.

Other packet reading features

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 device and trace file sources.

See also: coral_stop_all().

extern int (*coral_pkt_atm_hook)(coral_iface_t *iface, coral_pkt_buffer_t *packet,
	coral_atm_cell_t *cell);
If coral_pkt_atm_hook is not NULL, the user defined 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 processed 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 pkt_handler of coral_read_pkts(). The parameters are:
coral_iface_t *iface
pointer to the interface from which the cell was read
coral_pkt_buffer_t *packet
pointer to a packet structure containing as much data about the data link level packet as was available in the first cell. packet is provided for convenient use with functions that take a coral_pkt_buffer_t parameter (e.g., coral_get_payload()).
coral_atm_cell_t *cell
pointer to the first cell (in network byte order).
The default value of coral_pkt_atm_hook is NULL.
int coral_get_payload(const coral_pkt_buffer_t *src, coral_pkt_buffer_t *dst);
src is a pointer to a datagram or packet (e.g., the packet parameter of pkt_handler()). coral_get_payload() skips past the lower level (outer) protocol encapsulation in src and fills in dst with information about the payload of src. dst->protocol will contain CORAL_PROTO_UNKNOWN if coral_get_payload() understands the src protocol but does not recognize the protocol of the payload. coral_get_payload() returns 0 if it successfully parsed the src protocol information, or -1 if libcoral does not know how to parse the protocol of src, there is an error in the src packet, the protocol information in src buffer was truncated, or src->protocol is unknown. The recognized protocols are listed in the Command Usage document. Protocol identifiers are formed by concatenating "CORAL_", the prefix, and the name; e.g., CORAL_DLT_ATM_RFC1483.
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 human-readable information about the lower level protocol into buf, which has length len. Returns the length of the string written into buf if successful, or -1 if vsnprintf() is not available on your system and buf is not NULL, or for any of the errors listed in the documentation for coral_get_payload().
int coral_get_payload_by_proto(const coral_pkt_buffer_t *src,
    coral_pkt_buffer_t *dst, int proto);
int coral_get_payload_by_layer(const coral_pkt_buffer_t *src,
    coral_pkt_buffer_t *dst, int layer);
These functions call coral_get_payload() repeatedly until they find a packet with protocol proto or layer layer, and copy that packet's information into *dst. If there are packets a multiple layers that match, the outermost matching packet is selected. Returns 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().
char *coral_get_net_pkt(const coral_pkt_buffer_t *buffer, int *protocol);
Obsolete. See coral_get_payload()

Packet reading example

static int handle_packet(coral_iface_t *iface, 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, handle_packet, NULL, NULL, 0, &count);
    printf("received %ld packets.\n", count);
    ...
}

Cell/Block Reading

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

General Description

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. All structures will be in network byte order. (In version 3.0, cells read from FATM devices had ATM headers in little endian order.)

If timeout is NULL (or not available), these functions will wait until data is 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 points to a user-defined function, it will be called when a new block of ATM cells is read by any of the cell reading functions.

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 set by previous calls to any reading functions on the same set of sources.

Return values

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);
By default, coral_read_cell_all() reads cells in the most efficient order (i.e., block order); but if the CORAL_OPT_SORT_TIME option is set, it will read them in time-sorted order (interleaving cells from different blocks). This assumes that all interfaces were started simultaneously when the trace was made. If the CORAL_OPT_SORT_TIME is set, timeout is ignored (it is always treated as NULL).
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, int 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, int interval);
These functions are like coral_read_cell() and coral_read_cell_all(), except that there is no timeout and they support intervals.

If interval > 0, then the CORAL_OPT_SORT_TIME option is automatically enabled, 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 filled in with the boundaries of the interval. When EOF is reached, the final partial interval is returned, and the next call will return NULL.

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);

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).

Related Functions

void (*coral_cell_block_hook)(const coral_iface_t *iface, coral_blk_info_t *binfo)
If coral_cell_block_hook points to a user-defined function, it 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_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 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.

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,
	long *sec, long *nsec);
These functions read the timestamp t, which was 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.

coral_read_clock_sec_nsec() splits the time into seconds and nanoseconds integer components, and writes them into *sec and *nsec, respectively.

coral_read_clock_double() returns the time as floating point number of seconds (to the nearest nanosecond). Note that some precision may be lost, especially when the time is normalized.

These functions automatically correct the case in which the FORE card doesn't increment the software clock because it misses a hardware clock wrap.

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_TIMESTAMP_TO_TIMESPEC(const coral_iface_t *iface, const coral_timestamp_t *t,
	struct timespec *tspec)
CORAL_TIMESTAMP_TO_TIMEVAL(const coral_iface_t *iface, const coral_timestamp_t *t,
	struct timeval *tval)
Converts a timestamp in t, which was read from interface iface, into a timespec in tspec or a timeval in tval.
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 function are used to step through all interfaces/sources, for example:
    coral_source_t *src = NULL;
    while ((src = coral_next_source(iface))) {
        coral_dump(src);
    }
const char *coral_source_get_filename(const coral_source_t *src);
Returns the file name of source src. 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);
Return a pointer to the source to which interface iface belongs, or NULL if iface is bad.
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. The types are:
CORAL_TYPE_FILE
CoralReef trace file
CORAL_TYPE_PCAP
pcap (tcpdump) trace file
CORAL_TYPE_FATM
FORE OC3 device
CORAL_TYPE_POINT
Apptel POINT device
int coral_interface_get_type(const coral_iface_t *iface);
Return the original type of interface iface, or return CORAL_TYPE_NONE if iface is invalid or its type is unknown. The type can be any of the device types listed in the description of coral_source_get_type.
int coral_interface_get_datalink(const coral_iface_t *iface);
Return the data link layer type of interface iface, or return -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_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.
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.
time_t coral_interface_get_capturetime(const coral_iface_t *iface);
Returns the time of the start of the capture on interface iface, or 0 if the time is unknown, or -1 if there was an error. The time is measured in seconds since 1970-01-01 00:00:00 Z.
const char *coral_proto_abbr(int protocol);
const char *coral_proto_desc(int protocol);
const char *coral_proto_str(int protocol);
Protocol is a CORAL_prefix_name constant (listed in the Command Usage document) indentifying a data link layer protocol. These functions return a pointer to a string describing protocol:
  • coral_proto_abbr, a short name (listed in the Command Usage document);
  • coral_proto_desc, a long description, or NULL;
  • coral_proto_str, a long description, or "unknown N".
int coral_proto_id(const char *name);
Returns a CORAL_prefix_name 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(int 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" and CoralReef was compiled with libz, the file will be gzipped. 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". Note: to ensure that all data are written, you must use coral_write_close(), do not rely on program exit to close the trace.
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.

Trace writing example

void stopper(int sig)
{
    stop = 1;	/* must use a flag, because coral_stop() is not async-safe */
}

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

    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);

    signal(SIGALRM, stopper);
    alarm(coral_get_duration());

    if (coral_start_all() < 0)
        exit(5);

    while (1) {
	if (stop) {
	    coral_stop_all();
	    stop = 0;
	}
        iface = coral_read_block_all(&binfo, &blk, NULL);
        if (!iface) {
            if (errno == EINTR) continue;
            break;
	}

        if (coral_write_block(writer, iface, binfo, blk) < 0)
            exit(6);
    }

    coral_close_all();
    coral_write_close(writer);
}

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 headers must be included:
	#include <pcap.h>
	#include <pcap-int.h>
int coral_iface_to_pcap(const coral_iface_t *iface, pcap_t *pcap);
Fills in *pcap with information from *iface. Returns 0 for success, or -1 to indicate an error.
int coral_pkt_to_pcap(const coral_iface_t *iface, const coral_timestamp_t *timestamp,
    const coral_pkt_buffer_t *pkt, struct pcap_pkthdr *hdr);
Fills in *hdr with information from *iface, *timestamp, and *pkt. Returns 0 for success, or -1 to indicate an error.

Example

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

	/* ... */

	if (coral_iface_to_pcap(iface, &pcap) < 0)
	    /* handle error */;
	pcap_dumper = pcap_dump_open(&pcap, filename);

	/* ... */

	iface = coral_read_pkt(&pkt_result, &interval_result);
	if (!iface)
	    /* handle error */;
	coral_pkt_to_pcap(iface, pkt_result.timestamp, pkt_result.packet,
	    &pcap_hdr);
	pcap_dump(pcap_dumper, &pcap_hdr, pkt_result.packet->buf);
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, the resulting pcap file will be corrupt.

Other

int coral_puts(const char *str);
Like 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_print_data(int indent, const u_char *data, size_t len);
Prints len bytes from data to stdout in a easily readable format: 16 hex values per line, with each line indented indent spaces.
void coral_print_cell(int indent, const coral_iface_t *iface,
    const coral_atm_cell_t *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.
void coral_print_pkt(coral_iface_t *iface, coral_timestamp_t *timestamp,
    void *layerp, coral_pkt_buffer_t *packet, coral_pkt_buffer_t *header,
    coral_pkt_buffer_t *trailer);
Prints packet and optionally header and trailer (which were read from iface) to stdout in an easily readable format, with the timestamp in seconds, each protocol layer up to *(int*)layerp expanded by fields, and the payload in hex.

coral_print_pkt() is suitable for use as a pkt_handler for coral_read_pkts().

void coral_dump(const coral_source_t *src);
void coral_dump_all(void);
Prints information about the indicated sources to the CoralReef errfile.
void coral_stats(const coral_source_t *src);
void coral_stats_all(void);
Prints statistics about the indicated sources to the CoralReef errfile.
unsigned long coral_in_cksum_add(unsigned long psum, const void *data,
    int len);
unsigned short coral_in_cksum_result(unsigned long psum);
Calculates the internet checksum of a buffer. 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.

opaque object types

coral_source_t
coral_iface_t
coral_writer_t
coral_timestamp_t

ATM block info

The coral_blk_info_t structure defined in <libcoral.h> is used by many functions. It has at least these members:
typedef struct {
    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 */
} coral_blk_info_t;
Note that the interface field may not correspond to the number of the iface pointer returned by the CoralReef reading functions.

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 {
        u_int gfc         : 4;	/* generic flow control */
        u_int vpvc        : 24;	/* virtual path + virtual circuit indicators */
        u_int oam_rm      : 1;	/* PTI: OAM/RM indicator (ie, not user data) */
        u_int congestion  : 1;	/* PTI: we don't use this */
        u_int sdu_type    : 1;	/* PTI: in AAL5, this marks end of SAR-SDU */
        u_int clp         : 1;	/* cell loss priority */
    } h;
    u_int ui;
};

ATM cell

As of version 3.2, the ATM cell structure is deprecated. We expect it to be disabled completely in the future, when different hardware, firmware, and configurations return cells in different formats.

The correct way to access the fields of a cell is with the new cell accessor functions.

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).
const char *coral_cell_hec(iface, cell);
Returns a pointer to the header error control byte of the ATM header of cell. Currently, this is always NULL.
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 structure below is documented 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;

ATM AAL5 trailer

typedef struct {
    u_char	cpcs_uu;	/* CPCS user-to-user inidication */
    u_char	cpi;		/* common part indicator */
    u_short	length;		/* length of CPCS PDU payload */
    u_int	crc;		/* cyclic redundancy check of CPCS PDU */
} aal5_trailer_t;

LLC/SNAP header (IEEE 802.2 and rfc1042)

typedef struct {
    u_char     llc_dsap;
    u_char     llc_ssap;
    u_char     llc_cntl;
    u_char     snap_org[3];
    u_short    snap_type;
} llcsnap_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) */
    char *buf;			/* data (aligned to a multiple of 4 bytes) */
    int protocol;		/* protocol */
} coral_pkt_buffer_t;

Statistics for packet API

typedef struct {
    unsigned long pkts_recv;	/* packets received */
    unsigned long pkts_drop;	/* packets dropped */
    unsigned long truncated;	/* packets truncated by insufficient capture */
    unsigned long driver_corrupt; /* cell looks bad from the capture device */
    unsigned long too_many_vpvc; /* too many simultaneous vpvc pairs */
    unsigned long buffer_overflow; /* AAL5 cell stream > MAX_PACKET_SIZE */
    unsigned long aal5_trailer;	/* AAL5 trailer had bad length
				   probably caused by driver_corrupt drops */
    unsigned long ok_packet;
} coral_pkt_stats_t;
Note that the cells_recv and cells_drop fields present in version 3.1 have been removed, for two reasons: they were ATM specific, and they required that intervals be aligned with blocks of ATM cells. ATM block data may now be obtained via coral_cell_block_hook.

Results for packet API

typedef struct {
    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) */
} coral_pkt_result_t;
typedef struct {
    struct timeval begin;               /* beginning of interval */
    struct timeval end;                 /* end of interval */
    coral_pkt_stats_t *stats;           /* statistics for interval */
} coral_interval_result_t;