The LFAP Application Program Interface Introduction ------------ This document describes a C language application program interface to the Lightweight Flow Admission Protocol (LFAP). The LFAP API performs only the encoding and decoding of LFAP messages. The implementation of all I/O, processing logic, and error handling is left to the user. This documentation assumes that the reader is familiar with the LFAP specification. Overview of API Use ------------------- LFAP describes a flexible and extensible message format. In order to preserve this in the API, encoding and decoding is done on individual Information Elements (IE's) rather than entire LFAP messages. The LFAP API consists of three primary components: (1) an LFAPIE struct for representing decoded LFAP Information Elements; (2) an LFAPBuffer struct for representing encoded LFAP messages; and (3) a collection of procedures for converting between these two representations. An application generally encodes an LFAP message as follows: o Initialize an LFAPBuffer structure either by calling lfap_buffer_init() for a new buffer or reusing an existing buffer by calling lfap_buffer_reset(). o Encode the message header with lfap_begin_message(). o Iterate through all desired Information Elements using lfap_add_IE() to append each one to the encoded message. o Call lfap_end_message() to finish up the encoding process. o The encoded message may then be retrieved from the buffer through the lfap_buffer_get_msg() macro. The length of the encoded message can be retrived through the lfap_buffer_get_msglen() macro. o When the encoded buffer is no longer needed, the user should either call lfap_buffer_free() to deallocate the memory or lfap_buffer_reset() to reuse the buffer. For message containing multiple record IE's, the process is a little more involed: o Multiple record IE's are delimited by calling lfap_begin_multiple() and lfap_end_multiple(). o The fixed information IE's within a multiple record IE are delimited by calling lfap_begin_fixed() and lfap_end_fixed(). This is optional but must be done before adding any individual records. o Each record within the multiple record IE is delimited by calling lfap_begin_record() and lfap_end_record(). o Example: A) lfap_begin_message() B) lfap_begin_multiple() C) lfap_begin_fixed() D) Call lfap_add_IE() for each fixed information IE. E) lfap_end_fixed() Note: steps C - E are optional. F) lfap_begin_record() G) Call lfap_add_IE() for each IE in the record. H) lfap_end_record() Repeat steps F - H for each record I) lfap_end_mutliple Repeat steps B - I for any additional multiple record IE's J) lfap_end_message The decoding process differs from encoding in that all messages are decoded the same way regardless of whether or not they contain multiple record IE's. An application decodes an LFAP message as follows: o Read LFAP_HEADER_SIZE bytes from the connection. o Decode the message length by calling lfap_decode_msglen(). This message length does NOT include the LFAP_HEADER_SIZE bytes already read. o Use this decoded message length to read the remainder of the message. o Initialize an LFAPBuffer structure either by calling lfap_buffer_init() for a new buffer or reusing an existing buffer by calling lfap_buffer_reset(). o Call lfap_buffer_insert to put the full message (including the header) into an LFAPBuffer (or alternatively the message can be read from the socket directly into an LFAPBuffer). o Decode the message header by calling lfap_get_header(). o Repeatedly call lfap_get_IE() until the method returns an LFAP_NODATA error. This will decode the first record. o Call lfap_next_record() to advance the cursor to the next record. o Repeat this process for any additional records until lfap_next_record() returns an LFAP_NODATA error indicating the end of the message. o Call lfap_buffer_free() to free the buffer or lfap_buffer_reset() to prepare the buffer for reuse. There is no distinction between fixed information IE's and individual record IE's. Each decoded record will contain all the IE's that are relevant to that record. Initializing an LFAPBuffer for Use ---------------------------------- NAME lfap_buffer_init SYNOPSIS #include "Lfap.h" int lfap_buffer_init(LFAPBuffer *lbuf, void *buf, int buflen); MT-LEVEL MT-Safe DESCRIPTION lfap_buffer_init() initializes the LFAPBuffer struct pointed to by lbuf. The LFAPBuffer will initially use the buffer starting at buf and continuing for buflen bytes. If buf is NULL, then a new buffer will be allocated with at least buflen bytes. If buflen is zero then a default size is used. During the encoding process, the buffer may be automatically resized to hold the encoded message. Thus, if the LFAPBuffer is initialized with a user allocated buffer, this buffer must be compatible with realloc(). This does not apply to buffers being used for decoding since the buffer is never resized. lfap_buffer_init() assumes that a user-supplied buffer is empty (i.e., does not contain any data). If a message to be decoded has already been read into the buffer, the end of message marker should be set by calling lfap_buffer_insert(). RETURN VALUES On success, lfap_buffer_init() returns LFAP_SUCCESS. Otherwise, it returns LFAP_ERROR, and the lfap_buffer_get_error() macro can be used to retrieve the specific error code. ERRORS If lfap_buffer_init() fails, lfap_buffer_get_error() will return one of the following: LFAP_NOMEM Not enough memory was available to allocate the buffer. LFAP_MSGSIZE The requested buffer size exceeds LFAP_MAX_MSGSIZE. SEE ALSO lfap_buffer_free, lfap_buffer_insert, lfap_buffer_reset, lfap_buffer_get_error Reusing an LFAPBuffer --------------------- NAME lfap_buffer_reset SYNOPSIS #include "Lfap.h" void lfap_buffer_reset(LFAPBuffer *lbuf); MT-LEVEL MT-Safe DESCRIPTION lfap_buffer_reset() allows an existing LFAPBuffer to be reused. RETURN VALUES None. ERRORS None. SEE ALSO lfap_buffer_free, lfap_buffer_init Freeing an LFAPBuffer --------------------- NAME lfap_buffer_free SYNOPSIS #include "Lfap.h" void lfap_buffer_free(LFAPBuffer *lbuf); MT-LEVEL MT-Safe DESCRIPTION lfap_buffer_free() frees any memory associated with an LFAPBuffer struct. It does NOT free the LFAPBuffer struct itself. RETURN VALUES None. ERRORS None. SEE ALSO lfap_buffer_init, lfap_buffer_reset Inserting data into an LFAPBuffer --------------------------------- NAME lfap_buffer_insert SYNOPSIS #include "Lfap.h" lfapui8_t* lfap_buffer_insert(LFAPBuffer *lbuf, int nbyte); MT-LEVEL MT-Safe DESCRIPTION lfap_buffer_insert() advances the end of message mark by 'nbyte' bytes and returns a pointer to the beginning of the newly appended block. This may trigger an automatic resize of the internal buffer. RETURN VALUES A pointer to the beginning of the appended block or NULL if the insertion failed. ERRORS If lfap_buffer_insert() fails, the lfap_buffer_get_error() macro will return one of the following: LFAP_NOMEM Not enough memory was available to resize the buffer. LFAP_MSGSIZE The buffer size would have exceeded LFAP_MAX_MSGSIZE. EXAMPLES lfap_buffer_insert() is generally used to place an encoded LFAP message read from the network into an LFAPBuffer for decoding. There are two ways this may be accomplished: a) Placing an existing message into an LFAPBuffer: void *buf; int buflen; LFAPBuffer lbuf; buf = message_to_be_decoded; buflen = length_of_buf; /* Initialize the LFAP buffer */ lfap_buffer_init(&lbuf, buf, buflen); /* Set the end of message mark */ lfap_buffer_insert(lbuf, buflen); b) Reading a message directly into an LFAPBuffer: void *buf; int msglen; LFAPBuffer lbuf; lfap_buffer_init(&lbuf, NULL, 0); buf = lfap_buffer_insert(lbuf, LFAP_HEADER_SIZE); if (buf == NULL) { printf("Could not allocate memory for LFAP Message.\n"); exit(1); } /* * Insert code to read LFAP_HEADER_SIZE bytes into buf */ msglen = lfap_decode_msglen(buf); buf = lfap_buffer_insert(lbuf, msglen); if (buf == NULL) { printf("Could not allocate memory for LFAP Message.\n"); exit(1); } /* * Insert code to read msglen bytes into buf */ SEE ALSO None. LFAPBuffer Macros ----------------- NAME Macros for accessing information in an LFAPBuffer SYNOPSIS #include "Lfap.h" DESCRIPTION Several of the internal members of an LFAPBuffer struct can be retrieved through macros defined in Lfap.h. The 'lbuf' argument to these macros is a pointer to an LFAPBuffer struct. lfap_buffer_get_msg(lbuf) Evaluates to a void* which points to the encoded message contained in the buffer. lfap_buffer_get_msglen(lbuf) Evaluates to the integer length of the encoded message in bytes. lfap_buffer_get_error(lbuf) Evaluates to the integer value of the last error code associated with this buffer. SEE ALSO None. User-Defined Memory Management ------------------------------ NAME lfap_buffer_alloc lfap_buffer_free SYNOPSIS #include "Lfap.h" typedef int (*lfap_buffer_alloc_t)(LFAPBuffer *lbuf, int nybte); typedef void (*lfap_buffer_free_t) (LFAPBuffer *lbuf); extern lfap_buffer_alloc_t lfap_buffer_alloc; extern lfap_buffer_free_t lfap_buffer_free; MT-LEVEL MT-Safe DESCRIPTION The LFAPBuffer manipulation routines use the methods lfap_buffer_alloc() and lfap_buffer_free() for all memory allocation and deallocation. These methods are actually global pointers to predefined routines that use the standard C functions malloc(), realloc(), and free() for memory management. These default methods can be replaced with custom memory management routines by reassigning these global pointers prior to making any calls into the LFAP API. lfap_buffer_alloc() resizes the internal buffer pointed to by the 'buf' field of the LFAPBuffer struct to hold at least 'nbyte' additional bytes. The 'buflen' field must be updated to reflect the new capacity of the buffer. lfap_buffer_free() deallocates the buffer pointed to by the 'buf' field of the LFAPBuffer struct. In addition, the LFAPBuffer struct contains an unused 'opt' field that can be used to store any bookkeeping data associated with the buffer. RETURN VALUES lfap_buffer_alloc should return LFAP_SUCCESS on success, LFAP_ERROR otherwise. lfap_buffer_free has no return value. ERRORS If lfap_buffer_alloc() fails, the err field of the LFAPBuffer struct should be set to one of the following: LFAP_NOMEM Not enough memory was available to allocate the buffer. LFAP_MSGSIZE The buffer size would have exceeded LFAP_MAX_MSGSIZE. EXAMPLES See the routines default_buffer_alloc() and default_buffer_free() in buffer.c of the LFAP API source code. SEE ALSO None. Encoding an LFAP Message ------------------------ NAME lfap_begin_message, lfap_end_message, lfap_begin_multiple, lfap_end_multiple, lfap_begin_fixed, lfap_end_fixed, lfap_begin_record, lfap_end_record, lfap_add_IE SYNOPSIS #include "Lfap.h" int lfap_begin_message(LFAPBuffer *lbuf, LFAPHeader *hdr); int lfap_end_message(LFAPBuffer *lbuf); int lfap_begin_multiple(LFAPBuffer *lbuf); int lfap_end_multiple(LFAPBuffer *lbuf); int lfap_begin_fixed(LFAPBuffer *lbuf); int lfap_end_fixed(LFAPBuffer *lbuf); int lfap_begin_record(LFAPBuffer *lbuf); int lfap_end_record(LFAPBuffer *lbuf); int lfap_add_IE(LFAPBuffer *lbuf, LFAPIE *ie); MT-LEVEL MT-Safe DESCRIPTION lfap_begin_message() is used to encode the header portion of an LFAP message. 'hdr' is a pointer to an LFAPHeader struct containing the information to be encoded. lfap_begin_message must be called after initializing the LFAPBuffer struct with a call to lfap_buffer_init() or lfap_buffer_reset() and before calling any other encoding routines. lfap_end_message() must be the last method called when encoding an LFAP message. This is required to properly set the length field in the message header. lfap_begin_multiple() and lfap_end_multiple() are used to delimit the beginning and end of a multiple record IE. Note that an LFAP message need not contain any multiple record IE's. lfap_begin_fixed() and lfap_end_fixed() are used to delimit the fixed information IE's of a multiple record IE. These must be called after lfap_begin_multiple() and before lfap_begin_record(). Note that a multiple record IE need not contain any fixed information, and thus the use of these methods is optional. lfap_begin_record() and lfap_end_record() are used to delimit the individual records of a multiple record IE. lfap_begin_record() must be called after lfap_begin_multiple() and after adding any pertinent fixed information. lfap_add_IE() is used to encode an individual information element into an LFAPMessage. 'ie' is a pointer to an LFAPIE struct containing the data to be encoded. The type field of this struct must be properly initialized since this determines the specific type of information contained in the struct. lfap_add_IE must be called within the confines of lfap_begin_message and lfap_end_message for a simple LFAP message or in the confines of lfap_begin_fixed/lfap_end_fixed or lfap_begin_record/lfap_end_record for a message containing multiple record IE's. Note that the type code of the LFAPIE struct cannot be LFAP_MULTIPLE_RECORD since multiple record IE's are encoded by using the lfap_begin_multiple() and lfap_end_multiple() methods described above. After the encoding process is completed with a call to lfap_end_message. The encoded message can be retrieved with lfap_buffer_get_msg() and lfap_buffer_get_msglen(). RETURN VALUE All the encoding routines return LFAP_SUCCESS on success, LFAP_ERROR otherwise. The lfap_buffer_get_error() macro can be used to retrieve the specific error code. ERRORS If an encoding routine fails, the lfap_buffer_get_error() macro will return one of the following: LFAP_NOMEM Not enough memory was available to encode the message. LFAP_MSGSIZE The message size would have exceeded LFAP_MAX_MSGSIZE. LFAP_NOTEMPTY lfap_begin_message() was passed an LFAPBuffer with with a non-zero message length. LFAP_INVAL Indicates one or more of the following: o lfap_add_IE() was passed an LFAPIE struct with an invalid type. o lfap_add_IE() was passed an LFAPIE struct with an LFAP_MULTIPLE_RECORD type. o The format of a record did not match the format of previous records in a multiple record IE SEE ALSO lfap_buffer_get_msg, lfap_buffer_get_msglen, lfap_buffer_get_error Determining the Length of an Incoming LFAP Message -------------------------------------------------- NAME lfap_decode_msglen SYNOPSIS #include "Lfap.h" int lfap_decode_msglen(void *buf); MT-LEVEL MT-Safe DESCRIPTION lfap_decode_msglen() decodes the length field of an LFAP message header. This enables an incoming TCP/IP stream to be divided into individual LFAP messages for processing. The 'buf' parameter should point to the beginning of an LFAP message fragment that is at least LFAP_HEADER_SIZE bytes in length. The method returns the length of the message body in bytes. This does not include the length of the LFAP message header (which is LFAP_HEADER_SIZE bytes in length). The entire message (header plus body) should be placed in an LFAPBuffer for decoding. RETURN VALUE Returns the length of the message body in bytes. ERRORS None. SEE ALSO lfap_buffer_insert Decoding an LFAP Message ------------------------ NAME lfap_get_header, lfap_get_IE, lfap_next_record SYNOPSIS #include "Lfap.h" int lfap_get_header(LFAPBuffer *lbuf, LFAPHeader *hdr); int lfap_get_IE(LFAPBuffer *lbuf, LFAPIE *ie); int lfap_next_record(LFAPBuffer *lbuf); MT-LEVEL MT-Safe DESCRIPTION lfap_get_header() is used to retrieve the header information from an LFAP message. 'hdr' is a pointer to an LFAPHeader struct allocated by caller. If successful, the method returns the decoded information in this struct. lfap_get_IE() decodes the next IE in a record. 'ie' is a pointer to an LFAPIE struct allocated by the caller. If successful, the method returns the decoded information in this struct. The caller must use the type field of the returned data to determine how the IE should be interpreted. Any pointers within the returned LFAPIE struct point to data stored in the LFAPBuffer; thus, the buffer should not be freed or reused until the IE has been fully processed. lfap_get_IE() generates an LFAP_NODDATA error to indicate that a record boundary has been reached. lfap_get_IE() will return all IE's associated with a given record; there is no distinction between fixed information IE's and individual record IE's. lfap_next_record() is used to advance the cursor to the next record in the message. This method should not be called until a previous call to lfap_get_IE has generated an LFAP_NODATA error. If the end of the message has been reached, lfap_next_record() will generate an LFAP_NODDATA error. RETURN VALUE All the decoding routines return LFAP_SUCCESS on success, LFAP_ERROR otherwise. The lfap_buffer_get_error() macro can be used to retrieve the specific error code. ERRORS If a decoding routine fails, the lfap_buffer_get_error() macro will return one of the following: LFAP_MSG_CORRUPTED The LFAP message was corrupted and could not be properly decoded. LFAP_MSG_VERSION_ERR The version field of the message header is not compatible with the LFAP API library being used for decoding. LFAP_NODATA Indicates the end of a record in response to lfap_get_IE() or the end of a message in response to lfap_next_record(). SEE ALSO lfap_buffer_get_error