/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) Microsoft Corporation // // SYNOPSIS // // Defines // /////////////////////////////////////////////////////////////////////////////// #include "radcommon.h" #include "clientstrie.h" #include SubNet::SubNet(uint32_t ipAddress, uint32_t width) throw () : address(ipAddress) { if (width == 0) { subNetMask = 0; firstUniqueBitMask = 0x80000000; } else if (width == 32) { subNetMask = 0xffffffff; firstUniqueBitMask = 0; } else { subNetMask = 0xffffffff; subNetMask >>= (32 - width); subNetMask <<= (32 - width); firstUniqueBitMask = 0x80000000; firstUniqueBitMask >>= width; } address &= subNetMask; } SubNet SubNet::SmallestContainingSubNet(const SubNet& subnet) const throw () { // Find the most significant bit where the addresses differ. uint32_t width = 0; for (uint32_t mask = 0x80000000; (mask != 0) && (subnet.address & mask) == (address & mask); (mask >>= 1), (++width)) { } return SubNet(address, width); } ClientNodePtr& ClientNodePtr::operator=(ClientNodePtr& rhs) throw () { if (p != rhs.p) { delete p; p = rhs.p; rhs.p = 0; } return *this; } ClientNode::Relationship ClientNode::RelationshipTo( const ClientNode& node ) const throw () { if (key == node.key) { return self; } else if (key.Contains(node.key)) { return parent; } else if (node.key.Contains(key)) { return child; } else { return brother; } } void ClientNode::SetChild(ClientNodePtr& node) throw () { // assert(node.get() != 0); WhichBranch(*node) = node; } inline ClientNode::ClientNode( const SubNet& subnet, IIasClient* client ) throw () : key(subnet), value(client) { } ClientNodePtr ClientNode::CreateInstance( const SubNet& subnet, IIasClient* client ) throw () { return ClientNodePtr(new ClientNode(subnet, client)); } void ClientNode::Write( const ClientNodePtr& branch, std::ostream& output, size_t startingIndent ) { for (size_t i = 0; i < startingIndent; ++i) { output.put(' '); } if (branch.get() != 0) { output << branch->Key() << ((branch->Value() != 0) ? " \n" : " \n"); Write(branch->zero, output, startingIndent + 2); Write(branch->one, output, startingIndent + 2); } else { output << "\n"; } } ClientNode::~ClientNode() throw () { } IIasClient* ClientTrie::Find(uint32_t ipAddress) const throw () { IIasClient* bestMatch = 0; for (const ClientNode* n = root.get(); n != 0 && n->Key().HasMember(ipAddress); n = n->WhichChild(ipAddress)) { if (n->Value() != 0) { // As we walk down the tree, we are finding longer and longer matches, // so the last one we find is the best. bestMatch = n->Value(); } } return bestMatch; } void ClientTrie::Insert(const SubNet& subnet, IIasClient* client) { Insert(root, ClientNode::CreateInstance(subnet, client)); } void ClientTrie::Write(std::ostream& output) const { ClientNode::Write(root, output); } void ClientTrie::Insert(ClientNodePtr& node, ClientNodePtr& newEntry) { if (node.get() == 0) { // We made it to the end of the branch, so we're a leaf. node = newEntry; } else { switch (node->RelationshipTo(*newEntry)) { case ClientNode::parent: { // This is an ancestor of ours, so keep walking. Insert(node->WhichBranch(*newEntry), newEntry); break; } case ClientNode::child: { // This is our child, ... newEntry->SetChild(node); // ... so we take its place in the tree. node = newEntry; break; } case ClientNode::brother: { // We found a brother, so our parent is missing. ClientNodePtr parent(node->CreateParent(*newEntry)); parent->SetChild(node); parent->SetChild(newEntry); node = parent; break; } case ClientNode::self: { if (node->Value() == 0) { node->SetValue(newEntry->Value()); } // Otherwise, this is a duplicate entry. We do nothing so that the // first entry in the UI will take precedence. break; } default: // assert(false); break; } } } std::ostream& operator<<(std::ostream& output, const SubNet& subnet) { output << std::hex << std::setfill('0') << std::setiosflags(std::ios_base::right) << std::setw(8) << subnet.IpAddress() << ':' << std::setw(8) << subnet.SubNetMask(); return output; } std::ostream& operator<<(std::ostream& output, const ClientTrie& tree) { tree.Write(output); return output; }