1 
2 /* Web Polygraph       http://www.web-polygraph.org/
3  * Copyright 2003-2011 The Measurement Factory
4  * Licensed under the Apache License, Version 2.0 */
5 
6 #include "base/polygraph.h"
7 
8 #include "runtime/AddrMap.h"
9 #include "runtime/HostMap.h"
10 
11 HostMap *TheHostMap = 0;
12 
13 
14 /* HostCfg */
15 
HostCfg(const NetAddr & anAddr)16 HostCfg::HostCfg(const NetAddr &anAddr)
17 	: theAddr(anAddr), theProtocol(Agent::pUnknown),
18 	theContent(0), theServerRep(0), theUniverse(0),
19 	theHostsBasedCfg(0), isSslActive(false) {
20 }
21 
22 
23 /* HostMap */
24 
HostMap(int aCapacity)25 HostMap::HostMap(int aCapacity):
26 	theStaticIndex((aCapacity + aCapacity/3 + 7) | 1), theCount(0) {
27 	HostCfg *const h = 0;
28 	while (!theStaticIndex.full())
29 		theStaticIndex.push(h);
30 }
31 
~HostMap()32 HostMap::~HostMap() {
33 	while (theStaticIndex.count())
34 		delete theStaticIndex.pop();
35 	while (theDynamicIndex.count())
36 		delete theDynamicIndex.pop();
37 }
38 
at(int idx) const39 HostCfg *HostMap::at(int idx) const {
40 	if (0 <= idx && idx < capacity())
41 		return theStaticIndex[idx];
42 	else
43 	if (capacity() <= idx && idx < 2*capacity()) {
44 		Assert(theDynamicIndex.capacity() == capacity());
45 		return theDynamicIndex[idx - capacity()];
46 	}
47 	return 0;
48 }
49 
at(const NetAddr & addr)50 HostCfg *HostMap::at(const NetAddr &addr) {
51 	int idx = -1;
52 	Assert(findIdx(addr, idx));
53 	return at(idx);
54 }
55 
serverRepAt(int idx)56 ServerRep *HostMap::serverRepAt(int idx) {
57 	if (HostCfg *cfg = at(idx))
58 		return cfg->theServerRep;
59 	return 0;
60 }
61 
sslActive(const NetAddr & addr)62 bool HostMap::sslActive(const NetAddr &addr) {
63 	int idx = -1;
64 	if (findIdx(addr, idx))
65 		return at(idx)->isSslActive;
66 	return false;
67 }
68 
findUniverse(const NetAddr & addr)69 ObjUniverse *HostMap::findUniverse(const NetAddr &addr) {
70 	int idx = -1;
71 	if (findIdx(addr, idx))
72 		return at(idx)->theUniverse;
73 	return 0;
74 }
75 
findUniverseAt(int idx)76 ObjUniverse *HostMap::findUniverseAt(int idx) {
77 	if (const HostCfg *const h = at(idx))
78 		return h->theUniverse;
79 	return 0;
80 }
81 
find(const NetAddr & addr)82 HostCfg *HostMap::find(const NetAddr &addr) {
83 	int idx = -1;
84 	return find(addr, idx);
85 }
86 
find(const NetAddr & addr,int & idx)87 HostCfg *HostMap::find(const NetAddr &addr, int &idx) {
88 	if (findIdx(addr, idx))
89 		return at(idx);
90 
91 	return 0;
92 }
93 
mapAndFind(const NetAddr & addr,int & idx)94 HostCfg *HostMap::mapAndFind(const NetAddr &addr, int &idx) {
95 	if (HostCfg * const hcfg = find(addr, idx))
96 		return hcfg;
97 
98 	if (!addr.isDomainName())
99 		return 0;
100 
101 	int ipIdx = -1;
102 	if (!TheAddrMap->find(addr, ipIdx))
103 		return 0;
104 
105 	const NetAddr ip(TheAddrMap->selectAddr(ipIdx).addrA(), addr.port());
106 	return find(ip, idx);
107 }
108 
findIdx(const NetAddr & addr,int & idx)109 bool HostMap::findIdx(const NetAddr &addr, int &idx) {
110 	if (addr.isDynamicName() && theDynamicIndex.empty()) {
111 		// this is the first dynamic name, create dynamic index
112 		theDynamicIndex.stretch(capacity());
113 		HostCfg *const h = 0;
114 		while (!theDynamicIndex.full())
115 			theDynamicIndex.push(h);
116 	}
117 
118 	if (!theDynamicIndex.empty() && addr.isDomainName())
119 		// for domain names, check theDynamicIndex first
120 		if (const char *dot = addr.addrA().chr('.')) {
121 			NetAddr suffixAddr(dot, addr.port());
122 			if (findIdxInIndex(theDynamicIndex, suffixAddr, idx)) {
123 				idx += capacity();
124 				return true;
125 			} else
126 			if (addr.isDynamicName()) {
127 				idx += capacity();
128 				return false;
129 			}
130 		}
131 
132 	Assert(!addr.isDynamicName());
133 
134 	return findIdxInIndex(theStaticIndex, addr, idx);
135 }
136 
findIdxInIndex(const Array<HostCfg * > & arr,const NetAddr & addr,int & idx) const137 bool HostMap::findIdxInIndex(const Array<HostCfg*> &arr, const NetAddr &addr, int &idx) const {
138 	bool res = false;
139 
140 	idx = hash0(addr);
141 	if (endSearch(arr, addr, idx, res))
142 		return res;
143 
144 	// try hash1 followed by linear search
145 	idx = hash1(addr);
146 	for (int i = arr.capacity(); i; --i) {
147 		if (endSearch(arr, addr, idx, res))
148 			return res;
149 		idx++;
150 		idx %= arr.capacity();
151 	}
152 
153 	Assert(false); // no empty slots left!
154 	return res;
155 }
156 
addAt(int idx,const NetAddr & addr)157 HostCfg *HostMap::addAt(int idx, const NetAddr &addr) {
158 	Assert(0 <= idx && idx < 2*capacity());
159 	Assert(addr);
160 	Assert(!at(idx));
161 	HostCfg *const h = new HostCfg(addr);
162 	if (idx < capacity())
163 		theStaticIndex[idx] = h;
164 	else {
165 		Assert(addr.isDynamicName());
166 		Assert(!theDynamicIndex.empty());
167 		theDynamicIndex[idx - capacity()] = h;
168 	}
169 	++theCount;
170 	return h;
171 }
172 
173 // returns true if there is no reason to search further (match or empty)
endSearch(const Array<HostCfg * > & arr,const NetAddr & addr,int idx,bool & res) const174 bool HostMap::endSearch(const Array<HostCfg*> &arr, const NetAddr &addr, int idx, bool &res) const {
175 	if (HostCfg *h = arr[idx]) {
176 		if (h->theAddr == addr)
177 			return res = true;
178 		return res = false;
179 	}
180 
181 	// found empty slot
182 	res = false;
183 	return true;
184 }
185 
hash0(const NetAddr & addr) const186 int HostMap::hash0(const NetAddr &addr) const {
187 	return addr.hash0() % capacity();
188 	//return abs((int)(addr.lna() + addr.port())) % capacity();
189 }
190 
hash1(const NetAddr & addr) const191 int HostMap::hash1(const NetAddr &addr) const {
192 	return addr.hash1() % capacity();
193 	//return abs((int)(addr.lna() ^ addr.port() + addr.net())) % capacity();
194 }
195