blob: 2a16269c1d95282c95021f4634072f8ef77ae7a0 [file] [log] [blame]
# if ! defined(TS_IP_MAP_HEADER)
# define TS_IP_MAP_HEADER
# include "ink_platform.h"
# include "ink_defs.h"
# include <ts/ink_inet.h>
# include <ts/IntrusiveDList.h>
# include <ts/ink_assert.h>
/** @file
Map of IP addresses to client data.
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
namespace ts { namespace detail {
/** Interval class.
This holds an interval based on a metric @a T along with
client data.
*/
template <
typename T, ///< Metric for span.
typename A = T const& ///< Argument type.
> struct Interval {
typedef T Metric; ///< Metric (storage) type.
typedef A ArgType; ///< Type used to pass instances of @c Metric.
Interval() {} ///< Default constructor.
/// Construct with values.
Interval(
ArgType min, ///< Minimum value in span.
ArgType max ///< Maximum value in span.
) : _min(min), _max(max) {}
Metric _min; ///< Minimum value in span.
Metric _max; ///< Maximum value in span.
};
class Ip4Map; // Forward declare.
class Ip6Map; // Forward declare.
/** A node in a red/black tree.
This class provides only the basic tree operations. The client
must provide the search and decision logic. This enables this
class to be a base class for templated nodes with much less code
duplication.
*/
struct RBNode {
typedef RBNode self; ///< self reference type
/// Node colors
typedef enum { RED, BLACK } Color;
/// Directional constants
typedef enum { NONE, LEFT, RIGHT } Direction;
/// Get a child by direction.
/// @return The child in the direction @a d if it exists,
/// @c NULL if not.
self* getChild(
Direction d //!< The direction of the desired child
) const;
/** Determine which child a node is
@return @c LEFT if @a n is the left child,
@c RIGHT if @a n is the right child,
@c NONE if @a n is not a child
*/
Direction getChildDirection(
self* const& n //!< The presumed child node
) const {
return (n == _left) ? LEFT : (n == _right) ? RIGHT : NONE;
}
/** Get the parent node.
@return A Node* to the parent node or a @c nil Node* if no parent.
*/
self* getParent() const { return const_cast<self*>(_parent); }
/// @return The color of the node.
Color getColor() const { return _color; }
/** Reverse a direction
@return @c LEFT if @a d is @c RIGHT, @c RIGHT if @a d is @c LEFT,
@c NONE otherwise.
*/
Direction flip(Direction d) {
return LEFT == d ? RIGHT : RIGHT == d ? LEFT : NONE;
}
/** Perform internal validation checks.
@return 0 on failure, black height of the tree on success.
*/
int validate();
/// Default constructor.
RBNode()
: _color(RED)
, _parent(0)
, _left(0)
, _right(0)
, _next(0)
, _prev(0) {
}
/// Destructor (force virtual).
virtual ~RBNode() { }
/** Rotate the subtree rooted at this node.
The node is rotated in to the position of one of its children.
Which child is determined by the direction parameter @a d. The
child in the other direction becomes the new root of the subtree.
If the parent pointer is set, then the child pointer of the original
parent is updated so that the tree is left in a consistent state.
@note If there is no child in the other direction, the rotation
fails and the original node is returned. It is @b not required
that a child exist in the direction specified by @a d.
@return The new root node for the subtree.
*/
self* rotate(
Direction d //!< The direction to rotate
);
/** Set the child node in direction @a d to @a n.
The @a d child is set to the node @a n. The pointers in this
node and @a n are set correctly. This can only be called if
there is no child node already present.
@return @a n.
*/
self* setChild(
self* n, //!< The node to set as the child
Direction d //!< The direction of the child
);
/** Remove this node from the tree.
The tree is rebalanced after removal.
@return The new root node.
*/
self* remove();
void clearChild(Direction dir) {
if (LEFT == dir) _left = 0;
else if (RIGHT == dir) _right = 0;
}
/** @name Subclass hook methods */
//@{
/** Structural change notification.
This method is called if the structure of the subtree rooted at
this node was changed.
This is intended a hook. The base method is empty so that subclasses
are not required to override.
*/
virtual void structureFixup() {}
/** Called from @c validate to perform any additional validation checks.
Clients should chain this if they wish to perform additional checks.
@return @c true if the validation is successful, @c false otherwise.
@note The base method simply returns @c true.
*/
virtual bool structureValidate() { return true; }
//@}
/** Replace this node with another node.
This is presumed to be non-order modifying so the next reference
is @b not updated.
*/
void replaceWith(
self* n //!< Node to put in place of this node.
);
//! Rebalance the tree starting at this node
/** The tree is rebalanced so that all of the invariants are
true. The (potentially new) root of the tree is returned.
@return The root node of the tree after the rebalance.
*/
self* rebalanceAfterInsert();
/** Rebalance the tree after a deletion.
Called on the lowest modified node.
@return The new root of the tree.
*/
self* rebalanceAfterRemove(
Color c, //!< The color of the removed node.
Direction d //!< Direction of removed node from parent
);
//! Invoke @c structure_fixup() on this node and all of its ancestors.
self* rippleStructureFixup();
Color _color; ///< node color
self* _parent; ///< parent node (needed for rotations)
self* _left; ///< left child
self* _right; ///< right child
self* _next; ///< Next node.
self* _prev; ///< Previous node.
};
}} // namespace ts::detail
/** Map from IP addresses to client data.
Conceptually this class maps the entire space of IP addresses to
client data. Client data is stored as a @c (void*). Memory
management of the data is left to the client. The interface
supports marking ranges of addresses with a specific client
data. Marking takes a painter's algorithm approach -- any marking
overwrites any previous marking on an address. Details of marking
calls are discarded and only the final results are kept. That is,
a client cannot unmark expliticly any previous marking. Only a
specific range of addresses can be unmarked.
Both IPv4 and IPv6 are supported in the same map. Mixed ranges are
not supported (any particular range of addresses must be a single
protocol but ranges of both types can be in the map).
Use @c mark to mark / set / add addresses to the map.
Use @c unmark to unset addresses (setting the client data to 0 does
@b not remove the address -- this is for the convenience of clients
that do not need data, only membership). @c contains tests for
membership and retrieves the client data.
Ranges can be marked and unmarked arbitrarily. The internal
representation keeps a minimal set of ranges to describe the
current addresses. Search time is O(log n) where n is the number
of disjoint ranges. Marking and unmarking can take O(log n) and
may require memory allocation / deallocation although this is
minimized.
*/
class IpMap {
public:
typedef IpMap self; ///< Self reference type.
class iterator; // forward declare.
/** Public API for intervals in the map.
*/
class Node : protected ts::detail::RBNode {
friend class iterator;
friend class IpMap;
public:
typedef Node self; ///< Self reference type.
/// Default constructor.
Node() : _data(0) {}
/// Construct with @a data.
Node(void* data) : _data(data) {}
/// @return Client data for the node.
virtual void* data() { return _data; }
/// Set client data.
virtual self& setData(
void* data ///< Client data pointer to store.
) {
_data = data;
return *this;
}
/// @return Minimum value of the interval.
virtual sockaddr const* min() const = 0;
/// @return Maximum value of the interval.
virtual sockaddr const* max() const = 0;
protected:
void* _data; ///< Client data.
};
/** Iterator over nodes / intervals.
The iteration is over all nodes, regardless of which node is
used to create the iterator. The node passed to the constructor
just sets the current location.
*/
class iterator {
friend class IpMap;
public:
typedef iterator self; ///< Self reference type.
typedef Node value_type; ///< Referenced type for iterator.
typedef int difference_type; ///< Distance type.
typedef Node* pointer; ///< Pointer to referent.
typedef Node& reference; ///< Reference to referent.
typedef std::bidirectional_iterator_tag iterator_category;
/// Default constructor.
iterator() : _tree(0), _node(0) {}
reference operator* (); //!< value operator
pointer operator -> (); //!< dereference operator
self& operator++(); //!< next node (prefix)
self operator++(int); //!< next node (postfix)
self& operator--(); ///< previous node (prefix)
self operator--(int); ///< next node (postfix)
/** Equality.
@return @c true if the iterators refer to the same node.
*/
bool operator==(self const& that) const;
/** Inequality.
@return @c true if the iterators refer to different nodes.
*/
bool operator!=(self const& that) const { return ! (*this == that); }
private:
/// Construct a valid iterator.
iterator(IpMap* tree, Node* node) : _tree(tree), _node(node) {}
IpMap* _tree; ///< Container.
Node* _node; //!< Current node.
};
IpMap(); ///< Default constructor.
~IpMap(); ///< Destructor.
/** Mark a range.
All addresses in the range [ @a min , @a max ] are marked with @a data.
@return This object.
*/
self& mark(
sockaddr const* min, ///< Minimum value in range.
sockaddr const* max, ///< Maximum value in range.
void* data = 0 ///< Client data payload.
);
/** Mark a range.
All addresses in the range [ @a min , @a max ] are marked with @a data.
@note Convenience overload for IPv4 addresses.
@return This object.
*/
self& mark(
in_addr_t min, ///< Minimum address (network order).
in_addr_t max, ///< Maximum address (network order).
void* data = 0 ///< Client data.
);
/** Mark an IPv4 address @a addr with @a data.
This is equivalent to calling @c mark(addr, addr, data).
@note Convenience overload for IPv4 addresses.
@return This object.
*/
self& mark(
in_addr_t addr, ///< Address (network order).
void* data = 0 ///< Client data.
);
/** Mark a range.
All addresses in the range [ @a min , @a max ] are marked with @a data.
@note Convenience overload.
@return This object.
*/
self& mark(
IpEndpoint const* min, ///< Minimum address (network order).
IpEndpoint const* max, ///< Maximum address (network order).
void* data = 0 ///< Client data.
);
/** Mark an IPv6 address @a addr with @a data.
This is equivalent to calling @c mark(addr, addr, data).
@note Convenience overload.
@return This object.
*/
self& mark(
IpEndpoint const* addr, ///< Address (network order).
void* data = 0 ///< Client data.
);
/** Unmark addresses.
All addresses in the range [ @a min , @a max ] are cleared
(removed from the map), no longer marked.
@return This object.
*/
self& unmark(
sockaddr const* min, ///< Minimum value.
sockaddr const* max ///< Maximum value.
);
/// Unmark addresses (overload).
self& unmark(
IpEndpoint const* min,
IpEndpoint const* max
);
/// Unmark overload.
self& unmark(
in_addr_t min, ///< Minimum of range to unmark.
in_addr_t max ///< Maximum of range to unmark.
);
/** Fill addresses.
This background fills using the range. All addresses in the
range that are @b not present in the map are added. No
previously present address is changed.
@note This is useful for filling in first match tables.
@return This object.
*/
self& fill(
sockaddr const* min,
sockaddr const* max,
void* data = 0
);
/// Fill addresses (overload).
self& fill(
IpEndpoint const* min,
IpEndpoint const* max,
void* data = 0
);
/// Fill addresses (overload).
self& fill(
in_addr_t min,
in_addr_t max,
void* data = 0
);
/** Test for membership.
@return @c true if the address is in the map, @c false if not.
If the address is in the map and @a ptr is not @c NULL, @c *ptr
is set to the client data for the address.
*/
bool contains(
sockaddr const* target, ///< Search target (network order).
void **ptr = 0 ///< Client data return.
) const;
/** Test for membership.
@note Covenience overload for IPv4.
@return @c true if the address is in the map, @c false if not.
If the address is in the map and @a ptr is not @c NULL, @c *ptr
is set to the client data for the address.
*/
bool contains(
in_addr_t target, ///< Search target (network order).
void **ptr = 0 ///< Client data return.
) const;
bool contains(
IpEndpoint const* target, ///< Search target (network order).
void **ptr = 0 ///< Client data return.
) const;
/** Remove all addresses from the map.
@note This is much faster than @c unmark.
@return This object.
*/
self& clear();
/// Iterator for first element.
iterator begin();
/// Iterator past last element.
iterator end();
/// @return Number of distinct ranges in the map.
size_t getCount() const;
/** Validate internal data structures.
@note Intended for debugging, not general client use.
*/
void validate();
/// Print all spans.
/// @return This map.
// self& print();
protected:
/// Force the IPv4 map to exist.
/// @return The IPv4 map.
ts::detail::Ip4Map* force4();
/// Force the IPv6 map to exist.
/// @return The IPv6 map.
ts::detail::Ip6Map* force6();
ts::detail::Ip4Map* _m4; ///< Map of IPv4 addresses.
ts::detail::Ip6Map* _m6; ///< Map of IPv6 addresses.
};
inline IpMap& IpMap::mark(in_addr_t addr, void* data) {
return this->mark(addr, addr, data);
}
inline IpMap& IpMap::mark(IpEndpoint const* addr, void* data) {
return this->mark(&addr->sa, &addr->sa, data);
}
inline IpMap& IpMap::mark(IpEndpoint const* min, IpEndpoint const* max, void* data) {
return this->mark(&min->sa, &max->sa, data);
}
inline IpMap& IpMap::unmark(IpEndpoint const* min, IpEndpoint const* max) {
return this->unmark(&min->sa, &max->sa);
}
inline IpMap& IpMap::fill(IpEndpoint const* min, IpEndpoint const* max, void* data) {
return this->fill(&min->sa, &max->sa, data);
}
inline bool IpMap::contains(IpEndpoint const* target, void** ptr) const {
return this->contains(&target->sa, ptr);
}
inline IpMap::iterator
IpMap::end() {
return iterator(this, 0);
}
inline IpMap::iterator
IpMap::iterator::operator ++ (int) {
iterator old(*this);
++*this;
return old;
}
inline IpMap::iterator
IpMap::iterator::operator--(int) {
self tmp(*this);
--*this;
return tmp;
}
inline bool
IpMap::iterator::operator == (iterator const& that) const {
return _tree == that._tree && _node == that._node;
}
inline IpMap::iterator::reference
IpMap::iterator::operator * () {
return *_node;
}
inline IpMap::iterator::pointer
IpMap::iterator::operator -> () {
return _node;
}
inline IpMap::IpMap() : _m4(0), _m6(0) {}
# endif // TS_IP_MAP_HEADER