/* ** Copyright (C) 2001-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ #ifndef _UTILS_H #define _UTILS_H #include "silk.h" RCSIDENTVAR(rcsID_UTILS_H, "$SiLK: utils.h 7644 2007-06-26 16:48:40Z mthomas $"); /* ** a collection of utility routines. ** ** Suresh L Konda */ #ifdef HAVE_GETOPT_LONG_ONLY # include #else # include "gnu_getopt.h" #endif #define isRunningOnNode() 0 /* ** ** sku-compat.c ** */ #if !HAVE_IMAXDIV # define imaxdiv sk_imaxdiv #endif imaxdiv_t sk_imaxdiv(intmax_t numer, intmax_t denom); /* * Do the integer division of 'numer' by 'denom'; return a * structure that contains the 'quot' (quotient) and the 'rem' * (remainder). * * Conforming to C99. */ #if !HAVE_MEMCCPY # define memccpy sk_memccpy #endif void *sk_memccpy(void *dst, const void *src, int c, size_t len); /* * Copy bytes from 'src' to 'dst' stopping after the first * occurance of 'c' or when 'len' octets have been copied, * whichever comes first. If 'c' was not found, NULL is returned; * else return value points to character after 'c' in 'dst'. * * Conforming to C99. */ #if !HAVE_TIMEGM # define timegm sk_timegm #endif time_t sk_timegm(struct tm *tm); /* * Does the reverse of gmtime(). Takes a time structure and * returns seconds since the epoch in the UTC timezone. * * No standard; common on Open Source systems. */ #if 0 int sk_snprintf( char *str, size_t size, const char *format, ...); /* * Replacement for snprintf() that always NUL terminates the string. */ int sk_vsnprintf( char *str, size_t size, const char *format, va_list args); /* * Replacement for vsnprintf() that always NUL terminates the string. */ #endif /* ** ** skbitmap.c ** */ typedef struct { uint32_t *map; uint32_t num_bits; uint32_t count; } sk_bitmap_t; /* Internal macros. Not for public use. */ #define _BMAP_INDEX(p) ((p) >> 5) #define _BMAP_OFFSET(p) (1 << ((p) & 0x1F)) #define _BMAP_IS_SET(b, p) ((b)->map[_BMAP_INDEX(p)] & _BMAP_OFFSET(p)) int skBitmapCreate(sk_bitmap_t **bitmap_out, uint32_t num_bits); /* * Create a new empty bitmap capable of holding 'num_bits' bits. * Return the bitmap in the location given by 'bitmap_out'. * Returns 0 if successful; -1 for a memory allocation error or if * num_bits is zero. */ void skBitmapDestroy(sk_bitmap_t **bitmap); /* * Destroy the bitmap at location given by 'bitmap'. */ void skBitmapClearAllBits(sk_bitmap_t *bitmap); /* * Turn OFF all the bits in 'bitmap' and set the high-bit count to * zero. */ uint32_t skBitmapGetSizeF(const sk_bitmap_t *bitmap); #ifdef SKBITMAP_DEBUG # define skBitmapGetSize(bitmap) skBitmapGetSizeF(bitmap) #else # define skBitmapGetSize(bitmap) ((bitmap)->num_bits) #endif /* * Return the number of bits that 'bitmap' can hold. */ uint32_t skBitmapGetHighCountF(const sk_bitmap_t *bitmap); #ifdef SKBITMAP_DEBUG # define skBitmapGetHighCount(bitmap) skBitmapGetHighCountF(bitmap) #else # define skBitmapGetHighCount(bitmap) ((bitmap)->count) #endif /* * Return the number of bits in 'bitmap' that are ON. */ int skBitmapGetBitF(const sk_bitmap_t *bitmap, uint32_t pos); #ifdef SKBITMAP_DEBUG # define skBitmapGetBit(bitmap, pos) skBitmapGetBitF(bitmap, pos) #else # define skBitmapGetBit(bitmap, pos) \ (((pos) >= (bitmap)->num_bits) \ ? -1 \ : (_BMAP_IS_SET((bitmap), (pos)) ? 1 : 0)) #endif /* * Return 1 if the bit at position 'pos' in 'bitmap' is ON; return * 0 if it is OFF. */ void skBitmapSetBitF(sk_bitmap_t *bitmap, uint32_t pos); #ifdef SKBITMAP_DEBUG # define skBitmapSetBit(bitmap, pos) skBitmapSetBitF(bitmap, pos) #else # define skBitmapSetBit(bitmap, pos) \ if (((pos)>=(bitmap)->num_bits) || _BMAP_IS_SET((bitmap), (pos))) { \ /* no-op */ \ } else { \ (bitmap)->map[_BMAP_INDEX(pos)] |= _BMAP_OFFSET(pos); \ ++(bitmap)->count; \ } #endif /* * Turn ON the bit at position 'pos' in 'bitmap'. Adjust the * bitmap's high-bit counter. */ void skBitmapClearBitF(sk_bitmap_t *bitmap, uint32_t pos); #ifdef SKBITMAP_DEBUG # define skBitmapClearBit(bitmap, pos) skBitmapClearBitF(bitmap, pos) #else # define skBitmapClearBit(bitmap, pos) \ if (((pos)>=(bitmap)->num_bits) || !_BMAP_IS_SET((bitmap),(pos))) { \ /* no-op */ \ } else { \ (bitmap)->map[_BMAP_INDEX(pos)] &= ~(_BMAP_OFFSET(pos)); \ --(bitmap)->count; \ } #endif /* * Turn OFF the bit at position 'pos' in 'bitmap'. Adjust the * bitmap's high-bit counter. */ typedef struct { uint32_t m_octets[4][256/32]; } skOctetMap_t; typedef struct { const skOctetMap_t *omap; uint16_t i_octet[4]; } skOctetMapIterator_t; /* Status of an iterator. */ typedef enum { /* More entries */ SK_ITERATOR_OK=0, /* No more entries */ SK_ITERATOR_NO_MORE_ENTRIES } skIteratorStatus_t; #define _OMAP_OCT_IS_SET(omap, o, ip) \ ((omap)->m_octets[(o)][_BMAP_INDEX(ip)] & _BMAP_OFFSET(ip)) #define _OMAP_IP_IS_SET(omap, ip) \ (_OMAP_OCT_IS_SET((omap), 0, (((ip) >> 24) & 0xFF)) && \ _OMAP_OCT_IS_SET((omap), 1, (((ip) >> 16) & 0xFF)) && \ _OMAP_OCT_IS_SET((omap), 2, (((ip) >> 8) & 0xFF)) && \ _OMAP_OCT_IS_SET((omap), 3, ((ip) & 0xFF))) void skOctetMapClear(skOctetMap_t *octetmap); /* * Zero all values in the 'octetmap'. */ #ifdef SKBITMAP_DEBUG # define skOctetMapGetIp(octetmap, ip) skOctetMapGetIpF(octetmap, ip) #else # define skOctetMapGetIp(octetmap, ip) \ (_OMAP_IP_IS_SET(octetmap, ip) ? 1 : 0) #endif int skOctetMapGetIpF(const skOctetMap_t *octetmap, uint32_t ip); /* * Return 1 if 'ip' is represented in the 'octetmap'; 0 otherwise. */ int skOctetMapIteratorInitialize( skOctetMapIterator_t *iter, const skOctetMap_t *octetmap); /* * Prepare the iterator 'iter' to iterate over the entries in the * 'octetmap'. */ skIteratorStatus_t skOctetMapIteratorNext( uint32_t *out_ip, skOctetMapIterator_t *iter); /* * Fill 'out_ip' with the next IP address represented by the * octetmap that is bound to the iterator 'iter'. Return * SK_ITERATOR_OK if 'out_ip' was filled with an IP address, or * SK_ITERATOR_NO_MORE_ENTRIES otherwise. */ void skOctetMapIteratorReset(skOctetMapIterator_t *iter); /* * Allow 'iter' to iterate again over the octetmap that is bound to * it. */ /* Private macro used by GET_MASKED_BITS and SET_MASKED_BITS. This * creates a 32-bit integer with the first `s' least-significat bits * turned on. */ #define _BITMASK(s) (((s) >= 32) ? (~(uint32_t)0) : (~((~(uint32_t)0) << (s)))) /* * GET_MASKED_BITS(x, o, s) * * Given an integer value (<=32 bits) x, return an integer * representing the set of bits within x starting at offset o (from * the least-significant bit) of size s in bits. Works on 32, 16, and * 8 bit integers. * * 76543210 GET_MASKED_BITS(x, 2, 4) would return the value represent by * ..xxxx.. the middle 4 bits of a single byte, as shown at the left. */ #define GET_MASKED_BITS(x, o, s) (((x) >> (o)) & _BITMASK((s))) /* * SET_MASKED_BITS(x, v, o, s) * * Given an integer variable (<=32 bits) x, sets x to the value * created by seting the set of bits within x starting at offset o * (from the least-significant bit) of size s in bits to v. This is * the setting equivalent to GET_MASKED_BITS. This works on variables * which are 32, 16, or 8 bit integers. */ #define SET_MASKED_BITS(x, v, o, s) \ ((x) = ((x) & (~(_BITMASK((s)) << (o)))) | (((v) & _BITMASK((s))) << (o))) /* * BITMAP_DECLARE(var_name, size); * * Declares the bitmap 'var_name' that will hold size bits numbered * from 0 to size-1. */ #define BITMAP_DECLARE(name, size) \ uint32_t name[((size) >> 5) + ((((size) & 0x1F) == 0) ? 0 : 1)] /* * BITMAP_INIT(name); * * Clears all the bits in the bitmap named 'name'. This macro must * appear in the same scope as the BITMAP_DECLARE() macro. */ #define BITMAP_INIT(name) memset(&name, 0, sizeof(name)) /* * BITMAP_SETBIT(name, pos); * is_set = BITMAP_GETBIT(name, pos); * * Set or get the bit as position 'pos' in bitmap 'name'. */ #define BITMAP_SETBIT(name, pos) \ ((name)[_BMAP_INDEX(pos)] |= _BMAP_OFFSET(pos)) #define BITMAP_GETBIT(name, pos) \ (((name)[_BMAP_INDEX(pos)] & _BMAP_OFFSET(pos)) ? 1 : 0) /* ** ** sku-app.c ** */ typedef int (*sk_msg_fn_t)(const char *, ...); /* * The type of message functions. These should use the same * semantics as printf. */ typedef int (*sk_msg_vargs_fn_t)(const char *, va_list); /* * The type of message functions with the arguments expanded to a * variable argument list. */ extern int skMsgNone(const char *, ...); /* * The null message function. Does nothing and returns zero. */ extern int skMsgNoneV(const char *, va_list); /* * The null message function. Does nothing and returns zero. */ typedef struct skAppContext skAppContext_t; /* * Struct that contains global information about the application: * its name, full path, options. */ extern void skAppRegister(const char *name); /* * Register the application. Other functions below assume you've * passed argv[0] as the value of 'name'. */ extern void skAppUnregister(void); /* * Destroy all data structures and free all memory associated with * this application. */ extern const char *skAppRegisteredName(void); /* * Return the name that was used to register the application. This * is the value that was passed to skAppRegister(). The return * value should be considered read-only. */ extern const char *skAppName(void); /* * Return a short name for the application. This is the basename * of the registered name. The return value should be considered * read-only. */ extern const char *skAppFullPathname(void); /* * Return the full path to application. This will consult the PATH * envar and cgetcwd() to find the complete path to the * application. The return value should be considered read-only. */ extern char *skAppDirParentDir(char *buf, size_t buf_len); /* * Return the application's directory's parent directory in 'buf', * a character array of buf_len bytes. e.g., if the rwfilter * application lives in "/usr/local/bin/rwfilter", this function * puts "/usr/local" into buf. Return value is a pointer to 'buf', * or NULL on error. */ void skAppUsage(void); /* * Print short usage information---telling the user to use the * ``--help'' option---to stderr and exit the application with a * FAILURE exit status. */ void skAppStandardUsage( FILE *fh, const char *usage_msg, const struct option *app_options, const char **app_help); /* * Print, to the 'fh' file handle, the current application's name, * the 'usage_msg', each option in 'app_options' and its 'app_help' * string. Returns control to the application. */ extern void skAppContextSet(skAppContext_t *a_context); /* * Use '*a_context' as the global application context. */ extern skAppContext_t *skAppContextGet(void); /* * Return the address of the application's global context. */ extern FILE *skAppSetErrStream(FILE *f); /* * Sets the error stream to 'f' for any messages printed with * skAppPrintErrV() or skAppUsage(). When 'f' is NULL, calling * skAppPrintErr(), skAppPrintErrV(), and skAppUsage() will result * in no output being generated. * * Returns the previous value of the error-stream. */ extern void skAppSetFuncPrintErr(sk_msg_vargs_fn_t fn); /* * skAppPrintErr() will call this funtion to print its arguments. * By default, skAppPrintErr() uses skAppPrintErrV(). */ extern void skAppSetFuncPrintSyserror(sk_msg_vargs_fn_t fn); /* * skAppPrintSyserror() will call this funtion to print its * arguments. By default, skAppPrintSyserror() uses * skAppPrintSyserrorV(). */ extern int skAppPrintErrV(const char *fmt, va_list args); /* * Prints the application name, a colon, the result of formatting * the arguments using v*printf(), and a newline to the stream set * by skAppContextSetErrStream, which defaults to stderr. * * This is the default function used by skAppPrintErr() to print * error messages. */ extern int skAppPrintSyserrorV(const char *fmt, va_list args); /* * Prints the application name, a colon, the result of formatting * the arguments using v*printf(), the result of calling * strerror(), and a newline to the stream set by * skAppContextSetErrStream, which defaults to stderr. * * This is the default function used by skAppPrintSyserror() to * print system error messages. */ #ifdef TEST_PRINTF_FORMATS #define skAppPrintErr printf #else extern int skAppPrintErr(const char *fmt, ...); #endif /* * Calls the function set by skAppSetFuncPrintErr()---which has the * default value skAppPrintErrV()---to format and print the * arguments using the given format 'fmt'. */ #ifdef TEST_PRINTF_FORMATS #define skAppPrintSyserror printf #else extern int skAppPrintSyserror(const char *fmt, ...); #endif /* * Calls the function set by skAppSetFuncPrintSyserror()---which * has the default value skAppPrintSyserrorV()---to format and * print the arguments using the given format 'fmt'. */ /* ** ** sku-options.c ** */ /* long option arg types */ #define NO_ARG 0 #define REQUIRED_ARG 1 #define OPTIONAL_ARG 2 /* macro to print whether switch requires an argument */ #define SK_OPTION_HAS_ARG(switch) \ (((switch).has_arg == REQUIRED_ARG) \ ? "Req Arg" \ : (((switch).has_arg == OPTIONAL_ARG) \ ? "Opt Arg" \ : (((switch).has_arg == NO_ARG) \ ? "No Arg" \ : "BAD 'has_arg' VALUE"))) /* name of option for app to load a dynamlic library */ #define OPT_DYNAMIC_LIBRARY "dynamic-library" /* generic types for dealing with opaque handles */ typedef void *clientData; typedef int (* optHandler)(clientData cData, int optIndex, char *optArg); typedef void (* usage_fn_t)(void); void skOptionsSetup(void); void skOptionsTeardown(void); void skOptionsSetUsageCallback(usage_fn_t fn); int optionsSetup(usage_fn_t fn); /* returns 0 (ok), 1 (not ok) */ void optionsTeardown(void); int optionsRegister(void *inOptions, optHandler handler, clientData cData); void skOptionsDefaultUsage(FILE *fh); /* * Print usage information about the default options that all * applications support to the named file handle. */ int optionsHandleConfFile(char *filename); /* * optionsHandleConfFile: * * Loads a configuration file. The configuration file consists of * a series of newline-terminated lines. A line consisting of * only whitespace, or whose first non-whitespace character is a * `#' character is ignored. All other lines should consist of a * single option name followed by the option's value (if any), * seperated by whitespace. Whitespace at the beginning and end * of the line is ignored. * * BUGS: * If you intersperse switches (options) and arguments, arguments * before the configuration file is parsed will not be seen. * * Return: * 0 if ok. -1 else */ int optionsParse(int argc, char **argv); /* * optionsParse: * Adjust the global options array to allow for the help * option. If help is selected by the user, call the stashed * usageFunction. Parse input options given a set of * pre-registered options and their handlers. For each * legitimate option, call the handler. * SideEffects: * The individual handlers update whatever datastruture they wish * to via the clientData argument to the handler. * Return: * optind which points at the first non-option argument passed if * all is OK. If not OK, the return -1 for error. */ /* ** ** sku-times.c ** */ typedef enum { /* do not change the way the time is displayed */ SK_TIMESTAMP_CURRENT, /* use the default mode of displaying the time */ SK_TIMESTAMP_DEFAULT, /* display the time as "MM/DD/YYYY hh:mm:ss[.sss]" */ SK_TIMESTAMP_MMDDYYYY, /* display the time as "YYYY/MM/DD:hh:mm:ss[.sss]" */ SK_TIMESTAMP_YYYYMMDD } sktimestamp_mode_t; typedef enum { /* do not change whether the fractional seconds are displayed */ SK_TIME_FRACSEC_CURRENT, /* display the fractional seconds if that is the default */ SK_TIME_FRACSEC_DEFAULT, /* force the fractional seconds to be displayed */ SK_TIME_FRACSEC_ON, /* do not display the fractional seconds */ SK_TIME_FRACSEC_OFF } sktime_fracsec_mode_t; #define SK_TIMESTAMP_STRLEN 28 /* * Minimum size of buffer to pass to sktimestamp_r(). */ void sktimestampSetMode( sktimestamp_mode_t tsm, sktime_fracsec_mode_t fsm); /* * Set the default mode that sktimestamp_r() uses for displaying * the time. To only change one value, use the *_CURRENT setting * for the other setting. The display of fractional seconds may be * controlled on each invocation of sktimestamp_r(). */ int sktimestampSuppressingFracSecs(void); /* * Return 1 if fractional seconds should be suppressed; 0 * otherwise; that is, return 0 if fractional seconds should be * printed, and 1 otherwise. */ char *sktimestamp_r( char *outbuf, const struct timeval *tval, int suppress_fracsec); /* * Fill 'outbuf' with an ASCII version of the time. 'outbuf' must * be at least SK_TIMESTAMP_STRLEN characters long. 'tval' is the * time (see gettimeofday(2)). * * If SiLK was NOT configured with the --enable-legacy-timestamps * switch, the timestamp will be in the form: * * "YYYY/MM/DD:HH:MM:SS.sss" * * where sss == milliseconds, and the time will be printed in the * local timezone. * * If SiLK was configured with --enable-legacy-timestamps, the * timestamp will be in the form: * * "MM/DD/YYYY HH:MM:SS" * * The value will be in UTC unless SiLK was configured with * --enable-local-timezone switch. * * */ char *sktimestamp( const struct timeval *tval, int suppress_fracsec); /* * Similar to sktimestamp_r(), except returns the value in a static * buffer. */ char *timestamp_r(uint32_t t, char *outbuf); /* * DEPRECATED. DO NOT USE IN NEW CODE. * * Legacy wrapper around sktimestamp_r(). 't' is seconds since the * UNIX epoch. */ char *timestamp(uint32_t t); /* * DEPRECATED. DO NOT USE IN NEW CODE. * * Legacy wrapper around timestamp_r(). */ int maxDayInMonth(int yr, int mo); /* * Return the maximum day in a given month/year * * NOTE: Months are in the 1..12 range and NOT 0..11 * */ /* ** ** sku-bigsockbuf.c ** */ int bigsockbuf(int sock, int direction, int size); /* * There is no portable way to determine the max send and receive * buffers that can be set for a socket, so guess then decrement * that guess by 2K until the call succeeds. If n > 1MB then the * decrement by .5MB instead. * * Returns size or -1 for error */ /* ** ** sku-filesys.c ** */ char *baseName(const char *fp); /* * Strip directory prefix from the file path fp. Returns a pointer * to a static string buffer. */ char *baseName_r(char *dest, const char *src, size_t dest_size); /* * Thread safe version of baseName() */ char *dirName(const char *fp); /* * Strip file name suffix from the file path fp. Returns a pointer * to a static string buffer. */ char *dirName_r(char *dest, const char *src, size_t dest_size); /* * Thread safe version of dirName() */ #define FILEIsATty(fd) isatty(fileno(fd)) /* * Returns 1 if the FILE* fd is a tty, 0 otherwise */ int isFIFO(const char *name); /* * Returns 1 if name exists and is a FIFO; returns 0 otherwise. */ int dirExists(const char *dName); /* * Returns 1 if dName exists and is a directory; returns 0 * otherwise. */ int fileExists(const char *fName); /* * Returns 1 if fName exists and is a regular file; returns 0 * otherwise. */ off_t fileSize(const char *fName); /* * Returns the size of the file fName. Returns 0 if file is empty * or if it does not exist; use fileExists() to check for existence */ #define getRLockFD(fd) silkFileLocks((fd), F_RDLCK, F_SETLK) #define getRLockFILE(fp) getRLockFD(fileno(fp)) /* * int ret = getRLockFD(int fd); // file descriptor * int ret = getRLockFILE(FILE *fp); // file pointer * * Get an exclusive read lock on the opened file. It does not * wait. * * Returns: 0 OK; 1 failed; * */ #define getRLockFD_Wait(fd) silkFileLocks((fd), F_RDLCK, F_SETLKW) #define getRLockFILE_Wait(fp) getRLockFD_Wait(fileno(fp)) /* * int ret = getRLockFD_Wait(int fd); // file descriptor * int ret = getRLockFILE_Wait(FILE *fp); // file pointer * * Get an exclusive read lock on the opened file. It waits till it * gets the lock indefinitely. * * Returns: 0 OK; 1 failed; * */ #define getWLockFD(fd) silkFileLocks((fd), F_WRLCK, F_SETLK) #define getWLockFILE(fp) getWLockFD(fileno(fp)) /* * int ret = getWLockFD(int fd); // file descriptor * int ret = getWLockFILE(FILE *fp); // file pointer * * Get an exclusive write lock on the opened file. It does not * wait. * * Returns: 0 OK; 1 failed; * */ #define getWLockFD_Wait(fd) silkFileLocks((fd), F_WRLCK, F_SETLKW) #define getWLockFILE_Wait(fp) getWLockFD_Wait(fileno(fp)) /* * int ret = getWLockFD_Wait(int fd); // file descriptor * int ret = getWLockFILE_Wait(FILE *fp); // file pointer * * Get an exclusive write lock on the opened file. It waits till * it gets the lock indefinitely. * * Input: the file descriptor * * Returns: 0 OK; 1 failed; * */ #define releaseLockFD(fd) silkFileLocks((fd), F_UNLCK, F_SETLK) #define releaseLockFILE(fp) releaseLockFD(fileno(fp)) /* * int ret = releaseLockFD(int fd); // file descriptor * int ret = releaseLockFILE(FILE *fp); // file pointer * * Release a previously locked file. * * Returns: 0 OK; 1 failed; * */ int silkFileLocks(int fd, short type, int cmd); /* * Perform a locking operation on the specified file. For use by * the convenience macros above, which see. */ char *skFindFile(const char *basename, char *buf, size_t bufsize, int verbose); /* * Find the given file 'basename' in one of several places: * * -- See if the environment variable named by the cpp macro * ENV_SILK_PATH (normally SILK_PATH) is defined. If so, check * for the file in: * * $SILK_PATH/share/silk/file_name * * $SILK_PATH/share/file_name * * $SILK_PATH/file_name (for historical resaons) * -- Take the full path to the application (/yadda/yadda/bin/app), * lop off the app's immediate parent directory---which leaves * /yadda/yadda---and check for the file in the: * * "/share/silk" subdir (/yadda/yadda/share/silk/file_name) * * "/share" subdir (/yadda/yadda/share/file_name) * * If found---and if the total path is less than 'bufsize-1' * characters---fills 'buf' with a full path to the file and * returns a pointer to 'buf'. * * If not found or if 'buf' is too small to hold the full path; * returns NULL and leaves 'buf' in an unknown state. */ char *findFile(const char *basename); /* * findFile(file_name); * * Legacy version of skFindFile(). Returns a value the caller * should free(). * * DO NOT USE IN NEW CODE. */ char *skutilsFindPluginPath( const char *dlPath, char *path, size_t path_len, int verbose); /* * Find the given plugin path, 'dlPath', in one of several places; * if found copy that location in the character array 'path'--whose * caller-allocated size if 'path_len'---and return 'path'; * otherwise return NULL. This routine checks: * * -- If 'dlPath' contains a slash, return NULL. * -- See if the environment variable named by the cpp macro * ENV_SILK_PATH (normally SILK_PATH) is defined. If so, check * for the plug-in in: * * $SILK_PATH/share/lib/dlPath * * $SILK_PATH/lib/dlPath * -- Take the full path to the application "/yadda/yadda/bin/app", * lop off the app's immediate parent directory--which leaves * "/yadda/yadda", and check for the plug-in in the: * * "/share/lib" subdir (/yadda/yadda/share/lib/dlPath) * * "/lib" subdir (/yadda/yadda/lib/dlPath) * * If 'verbose' is greater than 0, uses skAppPrintErr() to print * every directory it checks. * * Return NULL if 'dlPath' was not found; otherwise return a char* * which is the buffer passed into the subroutine. */ int openFile(const char *FName, int mode, FILE **fp, int *isPipe); /* * status = openFile(file, mode, &fp, &isPipe); * * Open 'file' as a pipe or as a regular file depending on whether * it is a gzipped file or not. A file is considered gzipped if * its name contains the string ".gz\0" or ".gz.". * * The name of the file is given in the C-string 'file'; 'mode' * determines whether to open 'file' for reading (mode==0) or * writing (mode==1). * * The file pointer to the newly opened file is put into 'fp'. The * value pointed to by 'isPipe' is set to 0 if fopen() was used to * open the file, or 1 if popen() was used. The caller is * responsible for calling fclose() or pclose() as appropriate. * * The function returns 0 on success, or 1 on failure. */ int mkDirPath(const char *directory); /* * mkDirPath: * make full directory path including parent if required * Input: char * path * Output: 0 on success, 1 on failure */ int copyFile(const char *srcPath, const char *destPath); /* * copyFile: * Copies the file "source" to "dest". "Dest" may be a file or a * directory. * Input: char * source * char * dest * Output: 0 on success, errno on failure. */ int moveFile(const char *srcPath, const char *destPath); /* * moveFile: * Moves the file "source" to "dest". "Dest" may be a file or a * directory. * Input: char * source * char * dest * Output: 0 on success, errno on failure. */ int skOpenPagerWhenStdoutTty( FILE **output_stream, char **pager); /* * Attempts to redirect the '*output_stream' to the paging program * '*pager.' * * If output changed so that it goes to a pager, 1 is returned; if * the output is unchanged, 0 is returned. If an error occurred in * invoking the pager, -1 is returned. * * If the '*output_stream' is NULL, it is assumed that the output * was being sent to stdout. If the '*output_stream' is not stdout * or not a terminal, no paging is preformed and 0 is returned. * * If '*pager' is NULL, the environment variable SILK_PAGER is * checked for the paging program; if that is NULL, the PAGER * environment variable is checked. If that is also NULL, no * paging is performed and 0 is returned. * * If there was a problem invoking the pager, an error is printed * and -1 is returned. * * If the pager was started, the *output_stream value is set to the * pager stream, and *pager is set to the name of the pager (if the * user's environment was consulted), and 1 is returned. To close * the pager, use the skClosePager() function, or call pclose() on * the *output_stream. * * Due to the race condition of checking the status of the child * process, it is possible for 1 to be returned even though the * pager has exited. In this case the tool's output will be lost. */ void skClosePager(FILE *output_stream, const char *pager); /* * If skOpenPagerWhenStdoutTty() returns a positive value, use this * function to close the pager stream. Prints an error if the * close fails. */ int skGetLine( char *out_buffer, size_t buf_size, FILE *stream, const char *comment_start); /* * Fill 'out_buffer' with the next non-blank, non-comment line read * from 'stream'. The caller should supply 'out_buffer' and pass * its size in the 'buf_size' variable. The return value is the * number of lines that were read to get a valid line. * * The final newline will be removed; if comment_start is provided, * it will also be removed from line. * * If a line longer than buf_size is found, out_buffer will be set * to the empty string but the return value will be positive. * * At end of file, 0 is returned and out_buffer is the empty * string. */ /* ** ** sku-ips.c ** */ int skComputeCIDR( uint32_t start_ip, uint32_t end_ip, uint32_t *new_start_ip); /* * Compute the largest CIDR block that starts and 'start_ip' and * contains no IPs larger than 'end_ip', and return the number of * bits that that CIDR block contains. For example: * * computeCIDR(2, 5, NULL) => 31 * * When 'new_start_ip' is not NULL, it's value is set to 0 if the * CIDR block completely contains all IPs between 'start_ip' and * 'end_ip'. Otherwise, its value is set to the IP that follows * that block covered by the CIDR block. This allows one to print * all CIDR blocks by using: * * do { * bits = computeCIDR(start, end, &new_start); * printf("%s/%d", num2dot(start), bits); * start = new_start; * } while (start != 0); * * Continuing the above example: * * computeCIDR(2, 5, &new) => 31, new => 4 * computeCIDR(4, 5, &new) => 31, new => 0 * * Returns -1 if end_ip < start_ip. */ /* ** ** sku-string.c ** */ #define MALLOCCOPY(a,b) {if (!((a)=strdup(b))) {fprintf(stderr,"MALLOCCOPY: Out of memory at %s:%d\n", __FILE__, __LINE__);exit(1);}} /* * Duplicate the C string 'b' into 'a'. Exits if not enough memory. */ char *num2dot(uint32_t ip); /* * Converts the integer form of an IPv4 IP address to the dotted-quad * version. ip is taken to be in native byte order; returns a * pointer to a static string buffer. * * Returns NULL on error. */ char *num2dot0(uint32_t ip); /* * Like num2dot(), but will zero-pad the octects: num2dot0(0) will * return "000.000.000.000" */ #define SK_NUM2DOT_STRLEN 16 char *num2dot_r(uint32_t ip, char *outbuf); /* * Thread safe version of num2dot(). The 'outbuf' should be at * least SK_NUM2DOT_STRLEN characters long. */ char *num2dot0_r(uint32_t ip, char *outbuf); /* * Thread safe version of num2dot0(). The 'outbuf' should be at * least SK_NUM2DOT_STRLEN characters long. */ uint32_t dot2num(const char *ip); /* * Converts the string buffer ip containing an IPv4 dotted-quad IP * address into an integer in the native byte order. * * Returns 0xFFFFFFFF on error. */ const char *skNameToAddr(const char *name, struct in_addr *addr); /* * Uses domain name resolution to convert 'name' to an IPV4 * address. * * Returns NULL on success, and error message on failure. */ char *tcpflags_string(uint8_t flags); /* * Return an 8 character string denoting which TCP flags are set. * If all flags are on, FSRPAUEC is returned. For any flag that is * off, a space (' ') appears in place of the character. Returns a * pointer to a static buffer. */ #define SK_TCPFLAGS_STRLEN 9 char *tcpflags_string_r(uint8_t flags, char *outbuf); /* * Thread-safe version of tcpflags_string(). The 'outbuf' should * be at least SK_TCPFLAGS_STRLEN characters long. */ int strip(char *line); /* * Strips all whitespace from the start and end of line. Modifies * line in place. */ void lower(char *cp); /* * Converts uppercase letters in cp to lowercase. Modifies the * string in place. */ void upper(char *cp); /* * Converts lowercase letters in cp to uppercase. Modifies the * string in place. */ int skStringParseNumberList( uint32_t **number_list, uint32_t *number_count, const char *input, uint32_t min_val, uint32_t max_val, uint32_t max_number_count); /* * Given a C-string containing a list---i.e., comma or hyphen * delimited set---of non-negative integers, e.g., "4,3,2-6", * allocate and return, via the 'number_list' parameter, an array * whose values are the numbers the list contains, breaking ranges * into a list of numbers. If duplicates appear in the input, they * will appear in the return value. Order is maintained. Thus * given the C-string 'input' of "4,3,2-6", the function will set * *number_list to a newly allocated array containing * {4,3,2,3,4,5,6}. The number of entries in the array is returned * in '*number_count'. The list of number is limited by the * 'min_val' and 'max_val' parameters; a 'max_val' of 0 means no * maximum. The maximum size of the array to be returned is given * by 'max_number_count'; when this value is 0 and max_value is not * zero, it is set to the number of possible values (1+max-min); * when max_number_count is 0 and max_value is 0, it is set to a * large (2^24) number of entries. In all cases, the function * tries to keep the returned array as small as possible. On * success, 0 is returned. * * INPUT: * number_list -- the address in which to return the array * number_count -- the address in which to store the * number valid elements in the returned array. * input -- the string buffer to be parsed * min_value -- the minimum allowed value in user input * max_value -- the maximum allowed value in user input. When * max_value is 0, there is no maximum. * max_number_count -- the maximum number of entries the array * returned in 'number_list' is allowed to have. * * The caller should free() the returned array when finished * processing. * * On error, an error message is printed (via skAppPrintErr()), and * -1 is returned. */ int skStringParseNumberListToBitmap( sk_bitmap_t *out_bitmap, const char *input); /* * Similar to skStringParseNumberList(), except that instead of * returning an array, bits are set in the sk_bitmap_t 'out_bitmap' * which the caller must have previously created. * * This function does NOT clear the bits in 'out_bitmap' prior to * setting the bits based on 'input. When re-using a bitmap, the * caller should first call skBitmapClearAllBits(). * * If an error occurs, -1 is returned and the bitmap will be left * in an unknown state. * * The input may have values from 0 to skBitmapGetSize(out_bitmap)-1. */ int skStringParseNumberListToBitArray( uint32_t *out_bitarray, const char *input, uint32_t bitarray_size); /* * Similar to skStringParseNumberList(), except that instead of * returning an array, bits are set in the bitfield array * 'out_bitarray'. 'out_bitarray' should have been declared with * * BITMAP_DECLARE('out_bitarray', 'bitarray_size'). * * The input may have values from 0 to (bitarray_size-1). */ uint8_t *skParseNumberList( const char *input, uint8_t minValue, uint8_t maxValue, uint8_t *returnValueCount); /* * skParseNumberList * * DEPRECATED. Use skStringParseNumberList() instead. */ int skStringParseIP(uint32_t *out_val, const char *ip_string); /* * Parses a C-string containing an IPv4 address or an integer and * sets the value pointed to by 'out_val' to the result. Leading * and trailing whitespace will be ignored. * * Returns a non-negative value and puts result into 'out_val' if * parsing was successful. A return value of 0 means that only the * IPv4 address or integer and whitespace were present. A positive * return value indicates that a value was parsed, but that * 'ip_string' contains additional non-whitespace text. The return * value is the position in the 'ip_string' where this additional * text begins. * * Returns -1 if 'ip_string' was empty; returns -2 if it contained * only whitespace; returns -3 if there was text that could not be * parsed, if the octet values are too large, or if octets are * missing. * * This routine will not parse IPs in CIDR notation; or rather, it * will parse the IP portion, but the return value will be the * position of the '/' character. To correctly parse IPs in CIDR * notation, use skStringParseWildcardIP(). */ int skIPStringToBitmap(uint32_t bitmap[4][8], const char *ip_string); /* * DEPRECATED. Use skStringParseWildcardIP() instead. */ int skStringParseWildcardIP( skOctetMap_t *octetmap, const char *ip_string); /* * Takes a C-string containing an IPv4 address and fills the * 'octetmap' with the result. * * Returns 0 and puts result into 'octetmap' if parsing was * successful; returns 1 if 'ip_string' was empty; returns 2 if it * contained only whitespace; returns -1 if there was text that * could not be parsed. Leading and trailing whitespace will be * ignored. * * The 'ip_string' can be in CIDR notation "1.2.3.0/24", in * ordinary dotted decimal notation "1.2.3.4", an integer 16909056, * an integer with a CIDR designation 16909056/24, or in SiLK * wildcard notation: a dotted-quad with an 'x' respresenting an * entire octet "1.2.3.x" (equivalent to "1.2.3.0/24"), or a dotted * quad with lists or ranges in any or all octets "1.2,3.4,5.6,7" * or "1.2.3.0-255". */ int skStringParseDatetime( struct timeval *time_val, const char *time_string, int *resulting_precision); /* * Attempts to parse the 'time_string' as a date in the form * YYYY/MM/DD[:HH[:MM[:SS[.sss]]]]. Sets *time_val to that time in * UNIX epoch seconds. Assumes the time in UTC unless SiLK was * configured with the --enable-local-timezone switch, in which * case the time is assumed to be in the local timezone. * * If 'resulting_precision' is non-null, it is filled with the * index of the last "section" of date parsed. If it is NULL, the * precision is not recorded, but parsing still occurs. * * The "sections" are: * 1. Years parsed * 2. Months parsed * 3. Days parsed * 4. Hours parsed * 5. Minutes parsed * 6. Seconds parsed * 7. Fractional seconds parsed * * Note that skStringParseDatetime() will return -1 if the * time_string does not contain at least Day precision. * * Return 0 on success. Returns -1 and prints an message on an * error; error contions include an empty string, malformed date, * or extra text after the date. */ int skStringParseDatetimeRange( struct timeval *start, struct timeval *end, const char *s_datetime, int *start_precision, int *end_precision); /* * Attempts to parse 's_datetime' as a datetime or a range of * datetimes. If only one date is found, it is stored in 'start' * and the seconds value of the end date is set to LONG_MAX. * * If two dash-separated dates are found, the first is stored in * 'start' and the second is stored in 'end'. * * If 'start_precision' is not NULL, it is filled with the index of * the last "section" of date parsed. If it is NULL, the precision * is not recorded, but parsing still occurs. * * Similarly, if 'end_precision' is not NULL and a second date was * parsed, it is filled with the index of the last "section" of * date parsed. If it is NULL, the precision is not recorded. See * skStringParseDatetime() for a description of "sections" of a date. * * Note that skStringParseDatetimeRange() will return -1 if either * date does not contain at least Day precision. * * Returns -1 if the date found is unparsable, or if a dash is * found, the date on either side is unparsable. * * Returns 1 if two dates are found and parsed, but the end-date is * earlier than the start_date. * * Returns 0 if dates are parsed correctly. */ int skDatetimeCeiling( struct timeval *ceiling_time, const struct timeval *time_val, int precision); /* * Takes 'time_val' and a 'precision' to which it was parsed---see * skStringParseDatetime() for a description of "sections" of a * date---and puts into 'ceiling_time' the latest-possible * timestamp that meets the precision. * * skStringParseDatetime() parses a time to the earliest-possible * timestamp that meets the constraints parsed. For example, * "1990/12/25:05" is assumed to mean "1990/12/25:05:00:00.000000". * Passing that value to skDatetimeCeiling() would result in the * timestamp for "1990/12/25:05:59:59.999999". * * skDatetimeCeiling() is commonly used to calculate the endpoint * for a range of dates. For example, "2004/12/25-2004/12/26:3" * should represent everything between "2004/12/25:00:00:00.000000" * and "2004/12/26:03:59:59.999999". * * The time is assumed to be in UTC unless SiLK was configured with * the --enable-local-timezone switch. The timezone is only a * factor for times that are coarser than hour precision. */ int skStringParseUint32( uint32_t *result_val, const char *int_string, uint32_t min_val, uint32_t max_val); /* * Attempts to parse the C string 'int_string' as an unsigned * 32-bit integer. In addition, verifies that the value is between * 'min_val' and 'max_val' inclusive. A 'max_val' of 0 is * equivalent to UINT32_MAX; i.e., the largest value that will fit * in a 32bit value. Puts the result into location pointed to by * 'result_val'. Ignores any whitespace around the number. * * Returns 0 and fills 'result_val' when 'int_string' contains only * a number and whitespace and the number is parsable and the * resulting value is within the limits. * * Returns a positive value and fills 'result_val' when * 'int_string' contains a value within the limits and contains * additional non-whitespace text. The return value is the index * into 'int_string' of the first non-whitespace character * following the successfully parsed number; e.g; "1 x" would set * *result_val to 1 and return 3. * * A negative return value signals an error: -1 if 'int_string' is * NULL; -2 if it is empty or contained only whitespace; -3 if * string is unparseable; -4 if value overflows the parser; -11 if * value is less than 'min_val'; -12 is value is greater than * 'max_val'. */ int skStringParseUint64( uint64_t *result_val, const char *int_string, uint64_t min_val, uint64_t max_val); /* * As skStringParseUint32(), except that it attempts to parse the * C-string 'int_string' as an unsigned 64-bit integer. */ /* options flags to pass to skStringParseHumanUint64() */ typedef enum { SK_HUMAN_NORMAL = 0, SK_HUMAN_LOWER_TRADITIONAL = 0, SK_HUMAN_UPPER_TRADITIONAL = 0, SK_HUMAN_LOWER_SI = 1, SK_HUMAN_UPPER_SI = 2, SK_HUMAN_MID_WS = 4, SK_HUMAN_MID_NO_WS = 0, SK_HUMAN_END_WS = 0, SK_HUMAN_END_NO_WS = 8 } skHumanFlags_t; int skStringParseHumanUint64( uint64_t *result_val, const char *int_string, skHumanFlags_t parse_flags); /* * Attempts to parse the C string 'int_string' as an unsigned * 64-bit integer, ignoring leading whitespace. In addition, * handles human suffixes such as k, m, g, and t. Puts the result * into location pointed to by 'result_val'. * * Returns a value >= 0 the string was parsable. Returns 0 when * nothing other than parsed whitespace was present. A positive * return value is the index into 'int_string' of the first * non-parsed character following the successfully parsed number; * e.g; "1x" would set *result_val to 1 and return 2. * * A negative return value signals an error: -1 if 'int_string; is * NULL; -2 if it is empty or contained only whitespace; -3 if * string is unparseable; -4 if value overflows the parser; -5 if * value underflows the parser; -6 if value is NAN. * * parse_flags is made by or-ing flags from skHumanFlags_t together. * These flags affect the parsing as follows: * SK_HUMAN_NORMAL use defaults * SK_HUMAN_LOWER_TRADITIONAL use 1024 instead of 1000 for k, etc. * SK_HUMAN_UPPER_TRADITIONAL use 1024 instead of 1000 for K, etc. * SK_HUMAN_LOWER_SI use 1000 instead of 1024 for k, etc. * SK_HUMAN_UPPER_SI use 1000 instead of 1024 for K, etc. * SK_HUMAN_MID_WS ignore white space between number & suffix * SK_HUMAN_MID_NO_WS don't parse white space betwn number & suffix * SK_HUMAN_END_WS parse & ignore white space after suffixn * SK_HUMAN_END_NO_WS do not parse white space after suffix */ int skStringParseDouble( double *result_val, const char *dbl_string, double min_val, double max_val); /* * Attempts to parse the C string 'dbl_string' as a floating point * value (double). In addition, verifies that the value is between * 'min_val' and 'max_val' inclusive. A 'max_val' of 0 is * equivalent to HUGE_VAL. Puts the result into location pointed * to by 'result_val'. Ignores any whitespace around the number. * * Returns 0 and fills 'result_val' when 'dbl_string' contains only * a number and whitespace and the number is parsable and the * resulting value is within the limits. * * Returns a positive value and fills 'result_val' when * 'dbl_string' contains a value within the limits and contains * additional non-whitespace text. The return value is the index * into 'dbl_string' of the first non-whitespace character * following the successfully parsed number; e.g; "1.1 x" would set * *result_val to 1.1 and return 5. * * A negative return value signals an error: -1 if 'dbl_string' is * NULL; -2 if it is empty or contained only whitespace; -3 if * string is unparseable; -4 if value overflows the parser; -5 if * value underflows the parser; -11 if value is less than * 'min_val'; -12 is value is greater than 'max_val'. */ /* TCP FLAGS HANDLING */ /* Sets any high-flags in 'flags' to high in 'var'. Other high-flags * in 'var' are not affected. */ #define TCP_FLAG_SET_FLAG( var, flags ) ((var) |= (flags)) /* Returns 1 if the high-flags in 'flags' are also high in 'var'; * returns 0 otherwise. */ #define TCP_FLAG_TEST( var, flags ) ( (((flag) & (var)) != 0) ? 1 : 0 ) /* Returns 1 if, for all high-flags in 'mask', the only high-bits in * 'var' are thost that are set in 'high'; return 0 otherwise. See * skStringParseTCPFlagsHighMask() for details. */ #define TCP_FLAG_TEST_HIGH_MASK( var, high, mask ) \ ( (((var) & (mask)) == ((high) & (mask))) ? 1 : 0 ) int skStringParseTCPFlags( uint8_t *result, const char *flag_string); /* * Parses 'flag_string' as a block of TCP flags. Flag strings can * only contain the following characters: * F (FIN) * S (SYN) * R (RESET) * P (PUSH) * A (ACK) * U (URGENT) * E (ECE) * C (CWR) * * Returns 0 when 'flag_string' contains only TCP flag characters and * whitespace. * * When an unrecognized character is seen, parsing stops and the * function returns the position (1-based) of the that character in * 'flag_string'---ie, returns the number of characters successfully * parsed. * * Assumes flag_string is a NULL-terminated string. Overwrites the * value of 'result'. */ int skStringParseTCPFlagsHighMask( uint8_t *high, uint8_t *mask, const char *flag_string); /* * Parses 'flag_string' as a high/mask pair of blocks of TCP flags. * Both the high and mask portions of the string are flag strings, * and are interpreted by skStringParseTCPFlags(). Any TCP flags * not listed in 'mask' can have any value; flags listed 'high' * must be set; flags listed in 'mask' but not in 'high' must be * low. It is an error if a flag is listed in 'high' but not in * 'mask'. * * For example: "AS/ASFR" means ACK,SYN must be high, FIN,RST must * be low, and the other flags--PSH,URG,ECE,CWR--may have any * value. * * If the string is unparsable as high/mask pairs, returns -1. * * If the high portion of the string contains a flag not found in * the mask portion of the string, returns -1. * * If successful, returns 0. * * The inputs 'high' and 'mask' are overwritten with the bitmap of * the flags set. */ /* Whether to support 8 bit TCP flags. */ #define TCP_8_BIT_FLAGS 1 /* * flag definitions. */ #define CWR_FLAG (1 << 7) /* 128 */ #define ECE_FLAG (1 << 6) /* 64 */ #define URG_FLAG (1 << 5) /* 32 */ #define ACK_FLAG (1 << 4) /* 16 */ #define PSH_FLAG (1 << 3) /* 8 */ #define RST_FLAG (1 << 2) /* 4 */ #define SYN_FLAG (1 << 1) /* 2 */ #define FIN_FLAG (1) /* 1 */ #endif /* _UTILS_H */ /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */