windows-nt/Source/XPSP1/NT/net/rras/ip/nat/rhizome.h

236 lines
9.7 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*
* rhizome.h
*
* author: John R. Douceur
* date: 28 April 1997
*
* This header file defines structures, function prototypes, and macros for
* the rhizome database. The code is object-oriented C, transliterated from
* a C++ implementation.
*
* The rhizome is a database that stores patterns containing wildcards.
* Each pattern defines a set of keys that it matches; if a pattern contains
* N wildcards, then it matches 2^N keys. Since each pattern can match
* multiple keys, it is possible for a given key to match multiple patterns
* in the database. The rhizome requires that all patterns stored therein
* have a strict hierarchical interrelationship. Two patterns may match no
* common keys (in which case the patterns are said to be independent), or
* one pattern may match all the keys matched by a second pattern as well as
* additonal keys (in which case the second pattern is said to be more general
* than the first, and the first more specific than the second). The database
* will not accept two patterns which match some keys in common but each of
* which also matches additional keys that the other does not.
*
* The database can be searched for patterns that match a given search key.
* When the database is searched for a given key, the most specifically
* matching pattern is found. If no patterns in the database match the key,
* an appropriate indication is returned.
*
* Because this code is C, rather than C++, it is not possible to hide as
* much of the implementation from the client code as one might wish.
* Nonetheless, there is an attempt to isolate the client from some of the
* implementation details through the use of macros. Below is described each
* of the functions and macros necessary to use the rhizome database.
*
*/
#ifndef _INC_RHIZOME
#define _INC_RHIZOME
#ifdef __cplusplus
extern "C" {
#endif
//
// Macros and definitions needed to duplicate GPC environment
//
#define GpcAllocMem(Addr, Len, _Tag) \
*(Addr) = ExAllocatePoolWithTag(NonPagedPool, (Len), (_Tag))
#define GpcFreeMem(Address, _Tag) \
ExFreePool((Address))
typedef NTSTATUS GPC_STATUS;
#define GPC_STATUS_SUCCESS STATUS_SUCCESS
#define GPC_STATUS_PENDING STATUS_PENDING
#define GPC_STATUS_FAILURE STATUS_UNSUCCESSFUL
#define GPC_STATUS_RESOURCES STATUS_INSUFFICIENT_RESOURCES
#define GPC_STATUS_NOTREADY STATUS_DEVICE_NOT_READY
#define GPC_STATUS_NOT_FOUND STATUS_NOT_FOUND
#define GPC_STATUS_CONFLICT STATUS_DUPLICATE_NAME
#define GPC_STATUS_INVALID_HANDLE STATUS_INVALID_HANDLE
#define GPC_STATUS_INVALID_PARAMETER STATUS_INVALID_PARAMETER
#define GPC_STATUS_NOT_SUPPORTED STATUS_NOT_SUPPORTED
#define GPC_STATUS_NOT_EMPTY STATUS_DIRECTORY_NOT_EMPTY
#define GPC_STATUS_TOO_MANY_HANDLES STATUS_TOO_MANY_OPENED_FILES
#define GPC_STATUS_NOT_IMPLEMENTED STATUS_NOT_IMPLEMENTED
#define GPC_STATUS_INSUFFICIENT_BUFFER STATUS_BUFFER_TOO_SMALL
#define GPC_STATUS_NO_MEMORY STATUS_NO_MEMORY
#define GPC_STATUS_IGNORED 1L
/*
* There are two basic structures employed: the RhizomeNode and the Rhizome.
* Ideally, these would be completely hidden from the client, but the macro
* GetReferenceFromPatternHandle requires knowledge of the structure's
* definition. It is strongly urged that the client not directly refer to any
* of the fields of either of these structures. To support the documentation
* of the accompanying rhizome.c file, these structures are annotated with
* internal comments, but these can be ignored by the reader who wishes only
* to understand how to write client code for the rhizome.
*
* The client refers to a pattern by its PatternHandle. This is typedefed to
* a pointer to RhizomeNode, but this fact should be ignored by the client,
* since it is an implementation detail.
*
*/
//#include <stdlib.h>
//#include <malloc.h>
struct _RhizomeNode
{
// This structure is used for both branch nodes and leaf nodes. The two
// are distinguished by the value of the pivot_bit field. For branch
// nodes, pivot_bit < keybits, and for leaf nodes, pivot_bit == keybits.
int pivot_bit; // for branch nodes, bit of key on which to branch
union
{
struct // data for branch node
{
struct _RhizomeNode *children[2]; // pointers to children in search
} branch;
struct // data for leaf node
{
void *reference; // reference value supplied by client
struct _RhizomeNode *godparent; // pointer to more general pattern
} leaf;
} udata;
char cdata[1]; // space for storing value, mask, and imask fields
};
typedef struct _RhizomeNode RhizomeNode;
struct _Rhizome
{
int keybits; // number of bits in key
int keybytes; // number of bytes in key, calculated from keybits
RhizomeNode *root; // root of search trie
};
typedef struct _Rhizome Rhizome;
// The client uses PatternHandle to refer to patterns stored in the database.
typedef RhizomeNode *PatternHandle;
/*
* The client interface to the rhizome is provided by five functions and two
* macros. It is expected that the client will first instantiate a database,
* either on the stack or the heap, and then insert patterns with corresponding
* reference information into the database. When the client then performs a
* search on a key, the client wishes to know which pattern most specifically
* matches the key, and it ultimately wants the reference information
* associated with the most specifically matching pattern.
*
*/
// A rhizome may be allocated on the stack simply by declaring a variable of
// type Rhizome. To allocate it on the heap, the following macro returns a
// pointer to a new Rhizome structure. If this macro is used, a corresponding
// call to free() must be made to deallocate the structure from the heap.
//
//#define NEW_Rhizome ((Rhizome *)malloc(sizeof(Rhizome)))
#define AllocateRhizome(_r) GpcAllocMem(&(_r), sizeof(Rhizome), NAT_TAG_RHIZOME)
#define FreeRhizome(_r) GpcFreeMem((_r), NAT_TAG_RHIZOME)
// Since this is not C++, the Rhizome structure is not self-constructing;
// therefore, the following constructor code must be called on the Rhizome
// structure after it is allocated. The argument keybits specifies the size
// (in bits) of each pattern that will be stored in the database.
//
void
constructRhizome(
Rhizome *rhizome,
int keybits);
// Since this is not C++, the Rhizome structure is not self-destructing;
// therefore, the following destructor code must be called on the Rhizome
// structure before it is deallocated. However, if the client code can be
// sure, based upon its usage of the database, that all patterns have been
// removed before the structure is deallocated, then this function is
// unnecessary.
//
void
destructRhizome(
Rhizome *rhizome);
// Once the Rhizome structure has been allocated and constructed, patterns can
// be inserted into the database. Each pattern is specified by a value and a
// mask. Each bit of the mask determines whether the bit position is specified
// or is a wildcard: A 1 in a mask bit indicates that the value of that bit is
// specified by the pattern; a 0 indicates that the value of that bit is a
// wildcard. If a mask bit is 1, then the corresponding bit in the value field
// indicates the specified value of that bit. Value and mask fields are passed
// as arrays of bytes.
//
// The client also specifies a reference value, as a void pointer, that it
// wishes to associate with this pattern. When the pattern is installed, the
// insertRhizome function returns a pointer to a PatternHandle. From the
// PatternHandle can be gotten the reference value via the macro
// GetReferenceFromPatternHandle.
//
// If the new pattern conflicts with a pattern already installed in the
// database, meaning that the two patterns match some keys in common but each
// also matches additional keys that the other does not, then the new pattern
// is not inserted, and a value of 0 is returned as the PatternHandle.
//
PatternHandle
insertRhizome(
Rhizome *rhizome,
char *value,
char *mask,
void *reference,
ulong *status);
// This function removes a pattern from the rhizome. The pattern is specified
// by the PatternHandle that was returned by the insertRhizome function. No
// checks are performed to insure that this is a valid handle, so the client
// must discard the handle after it has called removeRhizome.
//
void
removeRhizome(
Rhizome *rhizome,
PatternHandle phandle);
// This function searches the database for the pattern that most specifically
// matches the given key. The key is passed as an array of bytes. When the
// most specific match is found, the PatternHandle of that matching pattern is
// returned. From the PatternHandle can be gotten the reference value via the
// macro GetReferenceFromPatternHandle. If no pattern in the database is found
// to match the key, then a value of 0 is returned as the PatternHandle.
//
PatternHandle
searchRhizome(
Rhizome *rhizome,
char *key);
// To get the client-supplied reference value from a PatternHandle, the
// following macro should be used. The client should not make assumptions
// about the details of the RhizomeNode structure, nor should it even assume
// that the PatternHandle is a pointer to a RhizomeNode.
//
#define GetReferenceFromPatternHandle(phandle) ((PatternHandle)phandle)->udata.leaf.reference
#define GetKeyPtrFromPatternHandle(_r,phandle) (((PatternHandle)phandle)->cdata)
#define GetMaskPtrFromPatternHandle(_r,phandle) (((PatternHandle)phandle)->cdata + (_r)->keybytes)
#define GetKeySizeBytes(_r) ((_r)->keybytes)
#define GetNextMostSpecificMatchingPatternHandle(phandle) ((phandle)->udata.leaf.godparent)
#ifdef __cplusplus
}
#endif
#endif /* _INC_RHIZOME */