Commit d00f448e authored by Jonathon Duerig's avatar Jonathon Duerig

Basic skeleton. Not functional yet. Getting this working and then adding some...

Basic skeleton. Not functional yet. Getting this working and then adding some modules is what comes next.
parent 1c29f3c0
// Command.h
#ifndef COMMAND_H_STUB_2
#define COMMAND_H_STUB_2
class Command
{
public:
virtual void run(std::multimap<Time, Connection *> & schedule)
{
std::multimap<ElabOrder, Connection>::iterator pos
= global::connections.find(key);
if (pos != global::connections.end())
{
runConnect(&(pos->second));
}
}
protected:
virtual void runConnect(Connection * conn)=0;
// We use a key here and look up the connection only on a run()
// because some commands delete a connection and we don't want later
// commands to keep the reference around.
ElabOrder key;
};
class NewConnectionCommand : public Command
{
public:
virtual void run(std::multimap<Time, Connection *> &)
{
std::multimap<ElabOrder, Connection>::iterator pos
= global::connections.find(key);
if (pos == global::connections.end())
{
pos = global::connections.insert(make_pair(key, Command()));
pos->second.reset(elab, connectionModelExemplar.clone());
}
}
protected:
virtual void runConnect(Connection *)
{
}
};
class TrafficModelCommand : public Command
{
protected:
virtual void runConnect(Connection * conn)
{
}
};
class ConnectionModelCommand : public Command
{
protected:
virtual void runConnect(Connection * conn)
{
conn->addConnectionModelParam(*this);
}
public:
int type;
unsigned int value;
};
class SensorCommand : public Command
{
protected:
virtual void runConnect(Connection * conn)
{
conn->addSensor(*this);
}
public:
int type;
vector<char> parameters;
};
class ConnectCommand : public Command
{
protected:
virtual void runConnect(Connection * conn)
{
conn->connect();
}
};
class TrafficWriteCommand : public Command
{
protected:
virtual void runConnect(Connection * conn)
{
conn->addTrafficWrite(*this, schedule);
}
public:
unsigned int delta;
unsigned int size;
};
class DeleteConnectionCommand : public Command
{
public:
virtual void run(std::multimap<Time, Connection *> & schedule)
{
std::multimap<ElabOrder, Connection>::iterator pos
= global::connections.find(key);
if (pos != global::connections.end())
{
pos->second.cleanup();
global::connections.erase(pos);
}
}
protected:
virtual void runConnect(Connection * conn)
{
}
};
#endif
// CommandInput.h
// This is the abstract base class for various kinds of control
// input. Each input is broken down into one of a number of
// commands. 'nextCommand' attempts to read enough bytes to make up
// the next command while 'getCommand' returns the current command or
// NULL if the previous 'nextCommand' had failed to acquire enough
// bytes.
#ifndef COMMAND_INPUT_H_STUB_2
#define COMMAND_INPUT_H_STUB_2
class Command;
class CommandInput
{
public:
virtual Command * getCommand(void)
{
return currentCommand.get();
}
virtual void nextCommand(void)=0;
protected:
std::auto_ptr<Command> currentCommand;
};
#endif
// CommandOutput.h
// This is the base class which abstracts the messages sent to the monitor.
// To create your own CommandOutput concrete class, overwrite the
// writeMessage() method.
#ifndef COMMAND_OUTPUT_H_STUB_2
#define COMMAND_OUTPUT_H_STUB_2
class CommandOutput
{
public:
void eventMessage(string const & message, ElabOrder const & key)
{
if (message.size() <= 0xffff && message.size() > 0)
{
writeHeader(EVENT_TO_MONITOR, message.size(), key);
writeMessage(message.c_str(), message.size(), key);
}
else
{
logWrite(ERROR, "Event Control Message too big or 0. It was not sent. "
"Size: %ud", message.size());
}
}
private:
void writeHeader(int type, unsigned short size, ElabOrder const & key)
{
int bufferSize = sizeof(unsigned char)*2 + sizeof(unsigned short)*3
+ sizeof(unsigned long);
char buffer[bufferSize];
char * pos = buffer;
pos += saveChar(pos, special);
pos += saveShort(pos, size);
pos += saveChar(pos, key.transport);
pos += saveInt(pos, key.ip);
pos += saveShort(pos, key.localPort);
pos += saveShort(pos, key.remotePort);
writeMessage(buffer, bufferSize);
}
char * saveChar(char * buffer, unsigned char value)
{
memcpy(buffer, &value, sizeof(value));
return buffer + sizeof(value);
}
char * saveShort(char * buffer, unsigned short value)
{
unsigned short ordered = htons(value);
memcpy(buffer, &ordered, sizeof(ordered));
return buffer + sizeof(ordered);
}
char * saveInt(char * buffer, unsigned short value)
{
unsigned int ordered = htonl(value);
memcpy(buffer, &ordered, sizeof(ordered));
return buffer + sizeof(ordered);
}
protected:
virtual void writeMessage(char const * message, int count);
};
#endif
// Connection.cc
#include "lib.h"
#include "Connection.h"
#include "Time.h"
#include "ConnectionModel.h"
#include "TrafficModel.h"
#include "Sensor.h"
using namespace std;
void Connection::reset(Order const & newElab,
std::auto_ptr<ConnectionModel> newPeer)
{
elab = newElab;
peer = newPeer;
}
void Connection::setTraffic(std::auto_ptr<TrafficModel> newTraffic)
{
traffic = newTraffic;
}
void Connection::connect(void)
{
if (peer.get() != NULL)
{
peer->connect();
}
else
{
logWrite(ERROR,
"Connection model has not been initialized before a connect call");
}
}
void Connection::addTrafficWrite(TrafficWriteCommand const & newWrite
std::multimap<Time, Connection *> const & schedule)
{
if (traffic.get() != NULL)
{
Time nextTime = traffic->addWrite(newWrite);
if (nextTime != Time())
{
schedule.insert(make_pair(nextTime, this));
}
}
else
{
logWrite(ERROR,
"Traffic write was added before the traffic model was set");
}
}
void Connection::addSensor(SensorCommand const & newSensor)
{
measurements.addSensor(newSensor);
}
void Connection::captureSend(Time & packetTime, struct tcp_info * kernel,
struct tcphdr * tcp)
{
Sensor * head = measurements.getHead();
if (head != NULL && isConnected)
{
head->captureSend(packetTime, kernel, tcp, elab, bufferFull);
}
}
void Connection::captureAck(Time & packetTime, struct tcp_info * kernel,
struct tcphdr * tcp)
{
Sensor * head = measurements.getHead();
if (head != NULL && isConnected)
{
head->captureAck(packetTime, kernel, tcp, elab, bufferFull);
}
}
Time Connection::writeToConnection(Time const & previousTime)
{
WriteResult result = traffic->writeToPeer(peer.get(), previousTime);
if (!isConnected && result.isConnected)
{
planet = result.planet;
global::planetMap.insert(make_pair(planet, this));
}
else if (isConnected && result.isConnected
&& planet != result.planet)
{
global::planetMap.erase(planet);
planet = result;
global::planetMap.insert(make_pair(planet, this));
}
isConnected = result.isConnected;
bufferFull = result.bufferFull;
return result.nextWrite;
}
void cleanup(void)
{
if (isConnected)
{
global::planetMap.erase(planet);
}
}
// Connection.h
#ifndef CONNECTION_H_STUB_2
#define CONNECTION_H_STUB_2
class Time;
class ConnectionModel;
class TrafficModel;
class Sensor;
class Connection
{
public:
Connection();
Connection(Connection const & right);
Connection & operator=(Connection const & right);
// Called after the Connection is added to the map. Sets the
// elabOrder sorting element and sets up the Connection Model.
void reset(Order const & newElab,
std::auto_ptr<ConnectionModel> newPeer);
// Called when the monitor specifies which traffic model to use.
void setTraffic(std::auto_ptr<TrafficModel> newTraffic);
// Set a connection model parameter. Things like socket buffer
// sizes, whether Nagle's algorithm is used, etc.
void addConnectionModelParam(ConnectionModelCommand const & param);
// This starts an attempt to connect through the connection
// model. Called when the monitor notifies of a connect.
void connect(void);
// Notifies the traffic model of write information from the monitor.
void addTrafficWrite(TrafficWriteCommand const & newWrite,
std::multimap<Time, Connection *> const & schedule);
// Adds a particular kind of sensor when requested by the monitor.
void addSensor(SensorCommand const & newSensor);
// Notifies the sensors of a data packet which was sent.
void captureSend(Time & packetTime, struct tcp_info * kernel,
struct tcphdr * tcp);
// Notifies the sensors of an acknowledged packet which was received.
void captureAck(Time & packetTime, struct tcp_info * kernel,
struct tcphdr * tcp);
// Notifies the traffic model that a timer has expired on the
// scheduler.
Time writeToConnection(Time const & previousTime);
// Called just before a connection is removed from the map.
void cleanup(void);
private:
// There are two kinds of ordering. One is for commands from
// emulab. One is for the pcap analysis.
Order elab;
Order planet;
std::auto_ptr<ConnectionModel> peer;
std::auto_ptr<TrafficModel> traffic;
SensorList measurements;
bool isConnected;
bool bufferFull;
};
#endif
// ConnectionModel.h
#ifndef CONNECTION_MODEL_H_PELAB_2
#define CONNECTION_MODEL_H_PELAB_2
class ConnectionModel
{
};
#endif
// Decayer.cc
#include "lib.h"
#include "Decayer.h"
using namespace std;
Decayer::Decayer(int newValue, double newRate)
: original(newValue)
, decayed(newValue)
, decayRate(newRate)
{
}
void Decayer::reset(int newValue)
{
original = newValue;
decayed = newValue;
}
int Decayer::get(void)
{
return original;
}
void Decayer::decay(void)
{
decayed = decayed - decayed*decayRate;
}
bool Decayer::operator<(int right) const
{
return static_cast<int>(decayed) < right;
}
bool Decayer::operator<=(int right) const
{
return static_cast<int>(decayed) <= right;
}
bool Decayer::operator>(int right) const
{
return static_cast<int>(decayed) > right;
}
bool Decayer::operator>=(int right) const
{
return static_cast<int>(decayed) >= right;
}
bool Decayer::operator==(int right) const
{
return static_cast<int>(decayed) == right;
}
bool Decayer::operator!=(int right) const
{
return static_cast<int>(decayed) != right;
}
bool operator<(int left, Decayer const & right)
{
return right >= left;
}
bool operator<=(int left, Decayer const & right)
{
return right > left;
}
bool operator>(int left, Decayer const & right)
{
return right <= left;
}
bool operator>=(int left, Decayer const & right)
{
return right < left;
}
bool operator==(int left, Decayer const & right)
{
return right == left;
}
bool operator!=(int left, Decayer const & right)
{
return right != left;
}
// Decayer.h
// This is for an old value which will decay over time. We still want
// to access the old value, but for comparison purposes, we want to
// used the decayed value. For instance, if there is a maximum which
// slowly decreases over time to allow for fundamentally changed
// conditions.
// The decay is proportional to the currently decayed value. If the
// original value is 100 and the decay rate is 0.01, then the decayed
// value would start at 100 then after a single decay(), it would drop
// to 99, then 98.01, etc.
#ifndef DECAYER_H_PELAB_2
#define DECAYER_H_PELAB_2
class Decayer
{
public:
// A positive rate of decay reduces the decayed value over time
// (for maximums). A negative rate of decay increases the decayed
// value over time (for minimums).
Decayer(int newValue=0, double newRate=0.01);
// Resets the value to be decayed. The decayRate is constant.
void reset(int newValue);
// Get the original value which will be decayed.
int get(void);
// Decay a step.
void decay(void);
bool operator<(int right) const;
bool operator<=(int right) const;
bool operator>(int right) const;
bool operator>=(int right) const;
bool operator==(int right) const;
bool operator!=(int right) const;
// Default destruction and copy semantics are OK.
private:
int original;
double decayed;
double decayRate;
};
bool operator<(int left, Decayer const & right);
bool operator<=(int left, Decayer const & right);
bool operator>(int left, Decayer const & right);
bool operator>=(int left, Decayer const & right);
bool operator==(int left, Decayer const & right);
bool operator!=(int left, Decayer const & right);
#endif
// KernelTcp.cc
#include "lib.h"
#include "KernelTcp.h"
void kernelTcp_addNewPeer(fd_set * readable)
{
if (global::peerAccept != -1
&& FD_ISSET(global::peerAccept, readable))
{
struct sockaddr_in remoteAddress;
socklen_t addressSize = sizeof(remoteAddress);
int fd = accept(global::peerAccept, &remoteAddress, &addressSize);
if (fd != -1)
{
// Add the peer.
int flags = fctl(fd, F_GETFL);
if (flags != -1)
{
int error = fctl(fd, F_SETFL, flags | O_NONBLOCK);
if (error != -1)
{
global::peers.push_back(
make_pair(fd, ipToString(remoteAddress.sin_addr.s_addr)));
addDescriptor(fd);
logWrite(PEER_CYCLE,
"Peer connection %d from %s was accepted normally.",
global::peers.back().first, global::peers.back().second);
}
else
{
logWrite(EXCEPTION, "fctl(F_SETFL) failed: %s", strerror(errno));
close(fd);
}
}
else
{
logWrite(EXCEPTION, "fctl(F_GETFL) failed: %s", strerror(errno));
close(fd);
}
}
else
{
logWrite(EXCEPTION, "accept() called on a peer connection failed: %s",
strerror(errno));
}
}
}
void kernelTcp_readFromPeers(fd_set * readable)
{
list<int>::iterator pos = global::peers.begin();
while (pos != peers.end())
{
if (FD_ISSET(pos->first, readable))
{
static const int bufferSize = 8096;
static char buffer[bufferSize];
int size = read(pos->first, buffer, bufferSize);
if (size == 0)
{
logWrite(PEER_CYCLE,
"Peer connection %d from %s is closing normally.",
pos->first, pos->second);
close(pos->first);
list<int>::iterator temp = pos;
++pos;
global::peers.erase(temp);
}
else if (size == -1 && errno != EAGAIN && errno != EINTR)
{
logWrite(EXCEPTION,
"Failed to read peer connection %d from %s so "
"I'm shutting it down: %s", pos->first, pos->second,
strerror(errno));
close(pos->first);
list<int>::iterator temp = pos;
++pos;
global::peers.erase(temp);
}
else
{
++pos;
}
}
else
{
++pos;
}
}
}
// KernelTcp.h
#ifndef KERNEL_TCP_H_PELAB_2
#define KERNEL_TCP_H_PELAB_2
#include "ConnectionModel.h"
enum ConnectionState
{
DISCONNECTED,
SOCKETED,
CONNECTED
};
class KernelTcp : public ConnectionModel
{
ConnectionState state;
int peersock;
int sendBufferSize;
int receiveBufferSize;
int maxSegmentSize;
bool useNagles;
};
void kernelTcp_addNewPeer(fd_set * readable);
void kernelTcp_readFromPeers(fd_set * readable);
void kernelTcp_packetCapture(fd_set * readable);
#endif
// Sensor.h
// This is the abstract base class for all of the individual
// measurement code, filters, and others. It includes code which
// allows a Sensor to represent a polymorphic list.
#ifndef SENSOR_H_STUB_2
#define SENSOR_H_STUB_2
class Sensor
{
public:
Sensor * getTail(void)
{
if (next.get() == NULL)
{
return this;
}
else
{
return next->getTail();
}
}
void addNode(std::auto_ptr<Sensor> node)
{
next=node;
}
void captureSend(Time const & packetTime, struct tcp_info const * kernel,
struct tcphdr const * tcp, Order const & elab,
bool bufferFull)
{
localSend(packetTime, kernel, tcp, elab, bufferFull);
if (next.get() != NULL)
{
next->captureSend(packetTime, kernel, tcp, elab, bufferFull);
}
}
void captureAck(Time const & packetTime, struct tcp_info * kernel,
struct tcphdr * tcp, Order const & elab,
bool bufferFull)
{
localAck(packetTime, kernel, tcp, elab, bufferFull);
if (next.get() != NULL)
{
next->captureAck(packetTime, kernel, tcp, elab, bufferFull);
}
}
std::auto_ptr<Sensor> clone(void) const;
{
std::auto_ptr<Sensor> result(localClone());
if (next.get() != NULL)
{
result.next = next->clone();
}
return result;
}
private:
std::auto_ptr<Sensor> next;
protected:
virtual void localSend(Time const & packetTime,
struct tcp_info const * kernel,
struct tcphdr const * tcp, Order const & elab,
bool bufferFull)=0;
virtual void localAck(Time const & packetTime,
struct tcp_info const * kernel,
struct tcphdr const * tcp, Order const & elab,
bool bufferFull)=0;
virtual std::auto_ptr<Sensor> clone(void) const=0;
};
#endif
// SensorList.cc
#include "lib.h"
#include "SensorList.h"
using namespace std;
SensorList::SensorList()