Commit e52f7cae authored by Jonathon Duerig's avatar Jonathon Duerig
Browse files

Fixed conflict with older dijkstr patch.

parent e7620088
// Exception.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
// Exception.h defines all of the possible things that might go wrong with
// the program. Each one has a string associated with it that is printed
// to the user as output.
#ifndef EXCEPTION_H_IP_ASSIGN_1
#define EXCEPTION_H_IP_ASSIGN_1
#include <exception>
class StringException : public std::exception
{
public:
explicit StringException(std::string const & error)
: message(error)
{
}
virtual char const * what() const throw()
{
return message.c_str();
}
virtual void addToMessage(char const * addend)
{
message += addend;
}
virtual void addToMessage(string const & addend)
{
addToMessage(addend.c_str());
}
private:
string message;
};
class InvalidArgumentException : public StringException
{
public:
explicit InvalidArgumentException(std::string const & error)
: StringException("Invalid Argument: " + error)
{
}
};
#endif
......@@ -17,10 +17,8 @@ all: dijkstra
include $(TESTBED_SRCDIR)/GNUmakerules
dijkstra: dijkstra.o wgraph.o wgraph.h
$(CXX) $(CFLAGS) dijkstra.o wgraph.o $(LIBS) -o dijkstra
wgraph.o: wgraph.cc wgraph.h
dijkstra: dijkstra.o bitmath.o bitmath.h Exception.h SingleSource.h IpTree.h dijkstra.h
$(CXX) $(CFLAGS) dijkstra.o bitmath.o $(LIBS) -o dijkstra
client-install: dijkstra
$(INSTALL_PROGRAM) dijkstra $(DESTDIR)$(CLIENT_BINDIR)/dijkstra
......
// IpTree.h
#ifndef IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
#define IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
enum { IP_SIZE = 32 };
class IpTree
{
public:
IpTree()
: m_firstHop(0)
, m_depth(0)
{
}
void reset(void)
{
m_child[0].reset(NULL);
m_child[1].reset(NULL);
m_firstHop = 0;
m_childHops.clear();
m_depth = 0;
}
void addRoute(IPAddress ip, int newFirstHop, int depth = 0)
{
m_depth = depth;
if (depth < IP_SIZE)
{
IPAddress bit = (ip >> (IP_SIZE - depth - 1)) & 0x01;
if (m_child[bit].get() == NULL)
{
m_child[bit].reset(new IpTree());
}
m_child[bit]->addRoute(ip, newFirstHop, depth + 1);
}
else
{
m_firstHop = newFirstHop;
}
++(m_childHops[newFirstHop]);
}
void printRoutes(int parentFirstHop, HostHostToIpMap const & ip,
int source, IPAddress subnet)
{
if (m_childHops.empty())
{
return;
}
map<int,int>::iterator mostPos = findMostPos();
if (mostPos->first != parentFirstHop)
{
m_firstHop = mostPos->first;
map< int, pair<string,string> >::const_iterator pos;
pos = ip[source].find(m_firstHop);
if (pos != ip[source].end())
{
printRouteToSubnet(pos->second.first, pos->second.second,
ipToString(subnet << (IP_SIZE - m_depth)),
m_depth, 1);
// TODO: replace hardwired '1' with actual cost metric
}
else
{
throw StringException("Internal error: Corruption in data structures: Compressor::add()");
}
}
if (m_child[0].get() != NULL)
{
m_child[0]->printRoutes(mostPos->first, ip, source, subnet << 1);
}
if (m_child[1].get() != NULL)
{
m_child[1]->printRoutes(mostPos->first, ip, source,
(subnet << 1) + 1);
}
}
map<int,int>::iterator findMostPos(void)
{
map<int,int>::iterator pos = m_childHops.begin();
map<int,int>::iterator mostPos = pos;
int mostScore = mostPos->second;
++pos;
while (pos != m_childHops.end())
{
if (pos->second > mostScore)
{
mostPos = pos;
mostScore = mostPos->second;
}
++pos;
}
return mostPos;
}
private:
IpTree(IpTree const &);
IpTree & operator=(IpTree const &) { return *this; }
private:
auto_ptr<IpTree> m_child[2];
int m_firstHop;
map<int, int> m_childHops;
int m_depth;
};
class Compressor
{
private:
static const int shift_10 = IP_SIZE - 8;
static const IPAddress ip_10 = 10;
static const int shift_172_16 = IP_SIZE - 12;
static const IPAddress ip_172_16 = (172 << 8) + 16;
static const int shift_192_168 = IP_SIZE - 16;
static const IPAddress ip_192_168 = (192 << 8) + 168;
public:
Compressor()
: graph(NULL)
, ipMap(NULL)
{
}
~Compressor()
{
}
void compress(SingleSource const & newGraph, HostHostToIpMap const & newIp)
{
graph = &newGraph;
ipMap = &newIp;
root_10.reset();
root_172_16.reset();
root_192_168.reset();
std::set<std::string> implicitIp;
std::multimap< int,pair<string,string> >::const_iterator implicitPos;
std::multimap< int,pair<string,string> >::const_iterator implicitLimit;
implicitPos = (*ipMap)[graph->getSource()].begin();
implicitLimit = (*ipMap)[graph->getSource()].end();
for ( ; implicitPos != implicitLimit; ++implicitPos)
{
implicitIp.insert(implicitPos->second.second);
}
for (int i = 0; i < graph->getVertexCount(); ++i)
{
int dest = i;
if (dest != graph->getSource())
{
std::multimap< int, pair<string,string> >::const_iterator pos;
std::multimap< int, pair<string,string> >::const_iterator limit;
pos = (*ipMap)[dest].begin();
limit = (*ipMap)[dest].end();
for ( ; pos != limit; ++pos)
{
if (implicitIp.find(pos->second.first) == implicitIp.end())
{
IPAddress destIp = stringToIP(pos->second.first);
add(dest, destIp);
}
}
}
}
root_10.printRoutes(INT_MAX, *ipMap, graph->getSource(), ip_10);
root_172_16.printRoutes(INT_MAX, *ipMap, graph->getSource(),
ip_172_16);
root_192_168.printRoutes(INT_MAX, *ipMap, graph->getSource(),
ip_192_168);
}
private:
void add(int dest, IPAddress destIp)
{
int firstHop = graph->getFirstHop(dest);
if ((destIp >> shift_10) == ip_10)
{
root_10.addRoute(destIp, firstHop, IP_SIZE - shift_10);
}
else if ((destIp >> shift_172_16) == ip_172_16)
{
root_172_16.addRoute(destIp, firstHop, IP_SIZE - shift_172_16);
}
else if ((destIp >> shift_192_168) == ip_192_168)
{
root_192_168.addRoute(destIp, firstHop, IP_SIZE - shift_192_168);
}
else
{
map< int, pair<string,string> >::const_iterator pos;
pos = (*ipMap)[graph->getSource()].find(firstHop);
if (pos != (*ipMap)[graph->getSource()].end())
{
// TODO: Figure out what cost means
printRouteToIp(pos->second.first, pos->second.second,
ipToString(destIp), 1);
}
else
{
throw StringException("Internal error: Corruption in data structures: Compressor::add()");
}
}
}
private:
Compressor(Compressor const &);
Compressor & operator=(Compressor const &) { return *this; }
private:
IpTree root_10;
IpTree root_172_16;
IpTree root_192_168;
SingleSource const * graph;
HostHostToIpMap const * ipMap;
};
#endif
// SingleSource.h
#ifndef SINGLE_SOURCE_H_DISTRIBUTED_DIJKSTRA_1
#define SINGLE_SOURCE_H_DISTRIBUTED_DIJKSTRA_1
#include <boost/config.hpp>
#include <vector>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
class EdgeInsertException : public std::exception
{
public:
EdgeInsertException(int newSource, int newDest, int newCost)
: source(newSource)
, dest(newDest)
, cost(newCost)
{
setMessage(intToString(source), intToString(dest), intToString(cost));
}
void setMessage(string newSource, string newDest, string newCost)
{
message = "Could not insert edge: source=" + newSource + ", dest="
+ newDest + ", cost=" + newCost;
}
virtual char const * what(void)
{
return message.c_str();
}
int getSource(void)
{
return source;
}
int getDest(void)
{
return dest;
}
int getCost(void)
{
return cost;
}
private:
string message;
int source;
int dest;
int cost;
};
class SingleSource
{
public:
SingleSource(int size)
: adj_graph(size)
, pred_map(size)
, dist_map(size)
, first_hop(size)
, vertexCount(size)
, source(0)
{
using namespace boost;
weightmap = get(edge_weight, adj_graph);
}
void insertEdge(int edgeSource, int edgeDest, int cost)
{
using namespace boost;
edge_descriptor edge;
bool inserted = false;
tie(edge, inserted) = add_edge(edgeSource, edgeDest, adj_graph);
if (!inserted)
{
throw EdgeInsertException(edgeSource, edgeDest, cost);
}
weightmap[edge] = cost;
}
void route(int newSource)
{
source = newSource;
using namespace boost;
// Compute the single-source shortest-path tree rooted at this vertex.
dijkstra_shortest_paths(adj_graph, vertex(source, adj_graph),
predecessor_map(&pred_map[0]).
distance_map(&dist_map[0]));
// set up the first_hop vector
first_hop[source] = source;
for (int i = 0; i < static_cast<int>(first_hop.size()); ++i)
{
if (i != source)
{
int current = i;
while(pred_map[current] != source)
{
current = pred_map[current];
}
first_hop[i] = current;
}
}
}
int getFirstHop(int index) const
{
return first_hop[index];
}
int getPred(int index) const
{
return pred_map[index];
}
int getDistance(int index) const
{
return dist_map[index];
}
int getVertexCount(void) const
{
return vertexCount;
}
int getSource(void) const
{
return source;
}
private:
// Use an adjacency_list graph instead of an adjacency_matrix
// graph, based on the assumption that there will be many fewer
// than V**2/2 edges. Represent the adjacencies with vectors
// instead of lists for traversal speed since the graph is not
// going to be changing a lot.
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
boost::no_property, boost::property < boost::edge_weight_t, int > >
Graph;
typedef boost::graph_traits < Graph >::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits < Graph >::edge_descriptor edge_descriptor;
typedef std::pair<int, int> Edge;
private:
Graph adj_graph;
boost::property_map<Graph, boost::edge_weight_t>::type weightmap;
std::vector<vertex_descriptor> pred_map;
std::vector<int> dist_map;
std::vector<int> first_hop;
int vertexCount;
int source;
};
#endif
// bitmath.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
#include <string>
#include <sstream>
#include "Exception.h"
#include "bitmath.h"
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
string ipToString(IPAddress ip)
{
static unsigned int charMask = 0x000000FF;
ostringstream buffer;
for (int i = 3; i >= 0; --i)
{
buffer << ((ip >> i*8) & charMask);
if (i > 0)
{
buffer << '.';
}
}
return buffer.str();
}
IPAddress stringToIP(string const & source)
{
size_t index = 0;
bool success = true;
IPAddress result = 0;
for (size_t i = 0; i < 4 && success; ++i)
{
istringstream buffer(source.substr(index));
IPAddress current = 0xf00;
buffer >> current;
if (current <= 0xff)
{
result = result | (current << ((3 - i)*8));
}
else
{
success = false;
}
index = source.find(".", index);
// if a dot is on the last iteration, then no dot should
// be found. Otherwise, there should be another dot.
if (i < 3)
{
success = !(index == string::npos);
}
else
{
success = (index == string::npos);
}
++index;
}
if (!success)
{
throw BadStringToIPConversionException(source);
}
return result;
}
// bitmath.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
// Utilities for dealing with ip numbers
#ifndef BITMATH_H_IP_ASSIGN_2
#define BITMATH_H_IP_ASSIGN_2
typedef unsigned int IPAddress;
class BadStringToIPConversionException : public StringException
{
public:
explicit BadStringToIPConversionException(string const & error)
: StringException("Bad String to IP conversion: " + error)
{
}
};
// A block is some binary number like 0x00010000 It is an ip address with
// all but one of its bits zero. This represents the number of hosts that
// can be in a particular subnet.
// A blockBit value is the number of bits inside of a particular block.
// For instance, in the example above, the blockBit value for that block
// is 16. The blockBit value of any block is log_2(Block).
// A count is the number of hosts that need to be contained by a Block.
// The blockBit value for a count is RoundUp(log_2(count)).
// take an unsigned int and produce a dotted quadruplet based on it.
// can throw bad_alloc
string ipToString(IPAddress ip);
IPAddress stringToIP(string const & source);
#endif
......@@ -7,26 +7,6 @@
date: March 6, 2002
*/
/*
Copyright 2003 by Steven S. Skiena; all rights reserved.
Permission is granted for use in non-commerical applications
provided this copyright notice remains intact and unchanged.
This program appears in my book:
"Programming Challenges: The Programming Contest Training Manual"
by Steven Skiena and Miguel Revilla, Springer-Verlag, New York 2003.
See our website www.programming-challenges.com for additional information.
This book can be ordered from Amazon.com at
http://www.amazon.com/exec/obidos/ASIN/0387001638/thealgorithmrepo/
*/
#include <iostream>
#include <map>
#include <string>
......@@ -34,171 +14,367 @@ http://www.amazon.com/exec/obidos/ASIN/0387001638/thealgorithmrepo/
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "wgraph.h"
#include "Exception.h"
#include "dijkstra.h"
#include "SingleSource.h"
#include "bitmath.h"
#include "IpTree.h"
using namespace std;
#define MAXINT 100007
// The command line options given to us.
namespace arg
{
string source;
bool runAll = true;
bool compress = false;
bool strong = true;
}
// Figure out what the users command line wishes are and set arg::*
// appropriately.
void processArgs(int argc, char * argv[]);
void execute(void);
// Translate the input into a convenient represenation
void inputEdges(SingleSource & graph, HostHostToIpMap & ip,
map<string, int> & nameToIndex, int numEdges);
// When we input edges, we translate the host labels into an internal
// numeric representation. When printing an error message, we want to
// translate the numbers involved back to the labels. This function
// serves that purpose. Note that this is a linear operation. But that
// is ok, because this function should only be used when presenting an
// error.
string reverseMap(int index, map<string,int> const & nameToIndex);