OverSim
BootstrapList.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2008 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
24 #include <BaseApp.h>
25 #include <BootstrapList.h>
26 #include <GlobalNodeList.h>
27 #include <BaseOverlay.h>
28 #include <NeighborCache.h>
30 #include <ZeroconfConnector.h>
31 #include <CommonMessages_m.h>
32 #include <hashWatch.h>
33 
34 #include <fstream>
35 #include <iostream>
36 
37 using namespace std;
38 
40 
41 std::ostream& operator<<(std::ostream& os, const BootstrapNodeHandle* n)
42 {
43  if (n == NULL) {
44  os << "<NULL>";
45  return os;
46  }
47 
48  if (n->isUnspecified()) {
49  os << "<unspec>";
50  } else {
51  os << n->getIp() << ":" << n->getPort() << " " << n->getKey()
52  << " last ping:" << n->getLastPing()
53  << " prio:" << n->getNodePrio();
54  }
55 
56  return os;
57 };
58 
59 
61 {
62  zeroconfConnector = NULL;
63  timerMsg = NULL;
64 }
65 
66 
68 {
69  cancelAndDelete(timerMsg);
70 }
71 
72 
74 {
75  if (stage != MIN_STAGE_COMPONENTS) {
76  return;
77  }
78 
79  mergeOverlayPartitions = par("mergeOverlayPartitions");
80  maintainList = par("maintainList");
81 
82  if (getParentModule()->getParentModule()->getSubmodule("zeroconfConnector", 0)) {
83  zeroconfConnector = check_and_cast<ZeroconfConnector *>(getParentModule()->
84  getParentModule()->getSubmodule("zeroconfConnector", 0));
85  if (!zeroconfConnector->isEnabled()) {
86  zeroconfConnector = NULL;
87  }
88  }
89 
90  // load local cache list only when using SingleHostUnderlayConfigurator
91  if (zeroconfConnector) {
92  ifstream nodeListFile("nodelist.dat", ios::in);
93  if (!nodeListFile) {
94  EV << "[BootstrapList::initializeApp() @ " << overlay->getThisNode().getIp()
95  << " (" << overlay->getThisNode().getKey() << ")]\n"
96  << " nodelist.dat not found"
97  << endl;
98  } else {
99  char address[16];
100  int port;
101  string key;
102  BootstrapNodeHandle *node;
103 
104  while (nodeListFile >> address >> port >> key) {
105  node = new BootstrapNodeHandle(OverlayKey(key, 16),
106  IPvXAddress(address), port,
107  CACHE);
108  if (node)
109  insertBootstrapCandidate(*node);
110  }
111  nodeListFile.close();
112 
113  //TODO
114  if (bootstrapList.size()) sendReadyMessage();
115  }
116  } else {
117  sendReadyMessage();
118  }
119 
120  WATCH_UNORDERED_MAP(bootstrapList);
121 
122  if (maintainList) {
123  timerMsg = new cMessage("BootstrapListTimer");
124  scheduleAt(simTime() + timerInterval, timerMsg);
125  }
126 }
127 
128 
130 {
131  if (msg == timerMsg) {
132  handleBootstrapListTimerExpired();
133  scheduleAt(simTime() + timerInterval, msg);
134  } else {
135  throw cRuntimeError("BootstrapList::handleTimerEvent(): "
136  "Received unknown self-message!");
137  }
138 }
139 
141 {
142  simtime_t current = simTime();
143  BootstrapNodeHandle *node;
144  BootstrapNodeSet::iterator iter;
145 
146  for (iter = bootstrapList.begin(); iter != bootstrapList.end(); iter++) {
147  node = iter->second;
148  if (timerInterval <= SIMTIME_DBL(current - node->getLastPing())) {
149  pingNode(*node);
150  }
151  }
152 }
153 
154 
156  cPolymorphic* context,
157  int rpcId, simtime_t rtt)
158 {
159  RPC_SWITCH_START(msg)
161  handleLookupResponse(_LookupResponse);
162  EV << "[BootstrapList::handleRpcResponse() @ "
163  << overlay->getThisNode().getIp()
164  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
165  << " Lookup RPC Response received: id=" << rpcId << "\n"
166  << " msg=" << *_LookupResponse << " rtt=" << rtt
167  << endl;
168  }
169  RPC_SWITCH_END( )
170 }
171 
173 {
174  EV << "[BootstrapList::handleLookupResponse() @ "
175  << overlay->getThisNode().getIp()
176  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
177  << " Lookup response for key " << msg->getKey()<< " : ";
178 
179  if (msg->getIsValid()) {
180  for (uint32_t i=0; i<msg->getSiblingsArraySize(); i++) {
181  if (msg->getSiblings(i).getKey() == msg->getKey()) {
182  EV << "Key " << msg->getSiblings(i)
183  << "belongs to a local node." << endl;
184  return;
185  }
186  }
187 
188  EV << "New partition discovered, going to join." << endl;
189  BootstrapNodeSet::iterator iter;
190  for (iter = bootstrapList.begin(); iter != bootstrapList.end(); iter++) {
191  if (iter->second->getKey() == msg->getKey())
192  overlay->joinForeignPartition(*iter->second);
193  }
194 
195  } else {
196  EV << "failed" << endl;
197  }
198 
199  return;
200 }
201 
202 
204  cPolymorphic* context,
205  int rpcId, simtime_t rtt)
206 {
207  NodeHandle &srcNode = pingResponse->getSrcNode();
208  BootstrapNodeSet::iterator iter;
209 
210  EV << "[BootstrapList::pingResponse() @ " << overlay->getThisNode().getIp()
211  << " (" << overlay->getThisNode().getKey() << ")]\n"
212  << " Ping response from node " << srcNode
213  << " with rtt " << rtt << endl;
214 
215  // update the lastPing field of the source node
216  if (!srcNode.isUnspecified())
217  if ((iter = bootstrapList.find(srcNode)) != bootstrapList.end())
218  iter->second->setLastPing(simTime());
219 
220  return;
221 }
222 
223 
225  const TransportAddress& dest,
226  cPolymorphic* context,
227  int rpcId)
228 {
229  EV << "[BootstrapList::pingTimeout() @ " << overlay->getThisNode().getIp()
230  << " (" << overlay->getThisNode().getKey() << ")]\n"
231  << " Ping timeout for node " << dest << endl;
232  // destination does not answer, remove it from the list
233  removeBootstrapCandidate(dest);
234 }
235 
236 
238 {
239  // ask neighborCache (discovery or re-join)
240  const TransportAddress temp = neighborCache->getBootstrapNode();
241  if (!temp.isUnspecified()) {
242  return temp;
243  }
244 
245  if (!maintainList) {
246  // TODO: add a parameter to return malicious bootstrap nodes also
247  return overlay->globalNodeList->getRandomNode(overlayId, -1, true,
248  true);
249  // return overlay->globalNodeList->getBootstrapNode();
250  } else {
251  const NodeHandle *bootstrapNode = &NodeHandle::UNSPECIFIED_NODE;
252  int i, j = 0;
253 
254  // pick a random node from the list
255  if (!bootstrapList.empty()) {
256  i = intrand(bootstrapList.size());
257  BootstrapNodeSet::iterator iter = bootstrapList.begin();
258 
259  while (j < i) {
260  iter++;
261  j++;
262  }
263 
264  bootstrapNode = (NodeHandle *)iter->second;
265  } else {
266  // if the list empty, get a bootstrap node from GlobalNodeList
267  if (!zeroconfConnector)
268  bootstrapNode = &overlay->globalNodeList->
269  getBootstrapNode(overlayId, overlay->getThisNode());
270  }
271  return *bootstrapNode;
272  }
273 }
274 
275 
277 {
278  Enter_Method_Silent();
279 
280  if ((overlay->getState() == BaseOverlay::READY) && (!node.isUnspecified())
281  && mergeOverlayPartitions) {
282  LookupCall* call = new LookupCall();
283  call->setBitLength(0);
284  call->setKey(node.getKey());
285  call->setNumSiblings(overlay->getMaxNumSiblings());
286  sendInternalRpcCall(OVERLAY_COMP, call);
287  }
288 
289  return;
290 }
291 
292 
295 {
296  Enter_Method_Silent();
297 
298  BootstrapNodeSet::iterator iter;
299  BootstrapNodeHandle *bootstrapNode;
300 
301  // if node already in the list, update its lastPing and nodePrio fields
302  if ((iter = bootstrapList.find(node)) != bootstrapList.end()) {
303  iter->second->setLastPing(simTime());
304  iter->second->setNodePrio(prio);
305 
306  return true;
307  }
308 
309  if ((bootstrapNode = new BootstrapNodeHandle(node, prio))) {
310  bootstrapNode->setLastPing(simTime());
311  bootstrapList.insert(NodePair(*bootstrapNode, bootstrapNode));
312  }
313 
314  locateBootstrapNode(node);
315 
316  return false;
317 }
318 
319 
321 {
322  Enter_Method_Silent();
323 
324  BootstrapNodeSet::iterator iter;
325 
326  node.setLastPing(simTime());
327 
328  // if node already in the list, update its lastPing and nodePrio fields
329  if ((iter = bootstrapList.find(node)) != bootstrapList.end()) {
330  iter->second->setLastPing(node.getLastPing());
331  iter->second->setNodePrio(node.getNodePrio());
332 
333  return true;
334  }
335 
336  bootstrapList.insert(NodePair(node, &node));
337  locateBootstrapNode(node);
338 
339  return false;
340 }
341 
342 
344 {
345  BootstrapNodeSet::iterator iter;
346  BootstrapNodeHandle* bootstrapNode;
347 
348  if (!addr.isUnspecified()) {
349  if ((iter = bootstrapList.find(addr)) != bootstrapList.end()) {
350  bootstrapNode = iter->second;
351  bootstrapList.erase(iter);
352  delete bootstrapNode;
353  }
354  }
355 
356  return;
357 }
358 
359 
361  int32_t overlayId)
362 {
363  overlay->globalNodeList->removePeer(node, overlayId);
364  // at this point, we consider this node not being able to provide the
365  // boot service anymore, therefore we have to revoke
366  // the service via zeroconfConnector
367  if (zeroconfConnector) {
368  zeroconfConnector->revokeService();
369  }
370 }
371 
372 
374  int32_t overlayId)
375 {
376  globalNodeList->registerPeer(node, overlayId);
377 
378  // at this point, we consider this node as booted and therefore have to
379  // announce the boot service for it via zeroconfConnector
380  if (zeroconfConnector) {
381  zeroconfConnector->announceService(node);
382  }
383 }
384 
385 
387 {
388  // dump the list of bootstrap nodes into the local cache only when
389  // using SingleHostUnderlayConfigurator
390  if (zeroconfConnector) {
391  ofstream nodeListFile("nodelist.dat", ios::out|ios::trunc);
392  if (!nodeListFile) {
393  std::cerr << "nodelist.dat could not be opened" << endl;
394  } else {
395  for (BootstrapNodeSet::iterator iter = bootstrapList.begin();
396  iter != bootstrapList.end(); iter++) {
397  nodeListFile << iter->second->getIp().str() << ' '
398  << iter->second->getPort() << ' '
399  << iter->second->getKey().toString(16) << '\n';
400  }
401  nodeListFile.close();
402  }
403  }
404 
405  // delete all bootstrap nodes and clear the list
406  for (BootstrapNodeSet::iterator iter = bootstrapList.begin();
407  iter != bootstrapList.end(); iter++) {
408  delete iter->second;
409  }
410 
411  bootstrapList.clear();
412 }