/* Web Polygraph http://www.web-polygraph.org/
* (C) 2003-2006 The Measurement Factory
* Licensed under the Apache License, Version 2.0 */
#include "base/polygraph.h"
#include "client/ConnHash.h"
#include "xstd/gadgets.h"
ObjFarm<ConnHashItem> ConnHash::TheItems;
ObjFarm<ConnHashQueueItem> ConnHash::TheQueueItems;
/* ConnHashItem */
ConnHashItem::ConnHashItem(): theCollision(0) {
}
void ConnHashItem::reset() {
theCollision = 0;
}
bool ConnHashItem::vacant() const {
return theQueue.count() == 0;
}
bool ConnHashItem::matches(const NetAddr &hopAddr, const NetAddr &tunnelAddr) const {
Assert(theQueue.count());
const Connection *conn = theQueue.firstOut()->conn;
// if tunnelAddr is undefined, check that connection tunnel end is as well
return conn->raddr() == hopAddr && conn->tunnelEnd() == tunnelAddr;
}
/* ConnHash */
ConnHash::ConnHash(int anCcAddrMax) {
if (anCcAddrMax)
ccAddrMax(anCcAddrMax);
}
void ConnHash::ccAddrMax(int aMax) {
theHash.stretch(Max(aMax|1, 7));
theHash.count(theHash.capacity());
TheItems.limit(1024); // magic, no good way to estimate
TheQueueItems.limit(1024); // magic, no good way to estimate
}
int ConnHash::hash(const NetAddr &addr) const {
return addr.addrN().hash0() % theHash.count();
}
bool ConnHash::find(const NetAddr &hopAddr, const NetAddr &tunnelAddr, ConnHashPos &pos) {
const int idx = hash(hopAddr);
pos = &theHash[idx];
while (ConnHashItem *hi = *pos) {
if (hi->matches(hopAddr, tunnelAddr))
return true;
pos = hi->nextPos();
}
return false;
}
bool ConnHash::find(const NetAddr &hostAddr, const NetAddr &tunnelAddr) {
ConnHashPos pos;
return find(hostAddr, tunnelAddr, pos);
}
void ConnHash::add(Connection *conn) {
ConnHashPos pos;
if (!find(conn->raddr(), conn->tunnelEnd(), pos))
*pos = TheItems.get();
ConnHashQueueItem *qi = TheQueueItems.get();
qi->conn = conn;
(*pos)->queue().enqueue(qi);
}
void ConnHash::delAt(ConnHashPos pos, ConnHashQueueItem *qi) {
TheQueueItems.put(qi);
ConnHashItem *hi = *pos;
if (hi->vacant()) {
*pos = hi->collision();
TheItems.put(hi);
}
}
Connection *ConnHash::delAt(ConnHashPos pos) {
Assert(*pos);
ConnHashItem *hi = *pos;
ConnHashQueueItem *qi = hi->queue().dequeue(hi->queue().lastIn()); // LIFO
Connection *conn = qi->conn;
delAt(pos, qi);
return conn;
}
void ConnHash::del(Connection *conn) {
ConnHashPos pos;
Assert(find(conn->raddr(), conn->tunnelEnd(), pos));
ConnHashItem *hi = *pos;
ConnHashQueueItem *qhead = hi->queue().firstOut();
ConnHashQueueItem *qi = qhead;
// XXX: this loop may be expensive if queues get long
// perhaps merge ConnHashQueueItem with Connection somehow?
do {
if (qi->conn == conn) {
hi->queue().dequeue(qi);
delAt(pos, qi);
return;
}
qi = (ConnHashQueueItem*)qi->next();
} while (qi != qhead);
Assert(false);
}
syntax highlighted by Code2HTML, v. 0.9.1