📄 endpointrouter.java
字号:
private synchronized void waitABit() {
// We'll still wake if something interresting happens.
try {
wait(500);
} catch (Exception e) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getAddress got an exception " + e + " while waiting");
}
}
/**
* Give a peer id, return an address to reach that peer.
* The address may be for a directly reachable peer, or
* for the first gateway along a route to reach the peer.
* If we do not have a route to the peer, we will use the
* Peer Routing Protocol to try to discover one. We will
* wait up to a minute for a route to be discovered.
*/
public EndpointAddress getAddress(String pId) {
// Compacting the cache first is a good idea if we want to
// get the best route. Note that compactCaches() can be expensive,
// but:
// - it is saving time and network bandwith ahead of time
// - the proces of compacting happens only if there has been
// a change in the caches.
//
// So, all together, this seems to be a good optimization.
//
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getAddress for ");
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug(" peer= " + pId);
Route route = null;
int count = 0;
while (true) {
// Then check if by anychance we can talk to it directly.
learnLocalRoute(pId);
// So, is there a local route ?
if (isLocalRoute(pId)) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("Found local address: " + pId + " -> " +
getLocalRoute(pId).toString());
return getLocalRoute(pId);
}
// Otherwise, look for a long route.
route = getRoute(pId);
EndpointAddress addr = null;
if (route != null) {
try {
addr = getLocalRoute(route.router);
if (addr != null) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("Found remote address: " + pId +
" -> " + addr.toString());
} else {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Found an not reachable route");
}
return addr;
} catch (Exception e) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getAddress for " + pId);
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug(" failed with " + e);
return null;
}
}
// Trying to recover a route
if (count == 0) {
// this is the first time in the loop.
findRoute(pId);
}
// Give up after at most 1 minute
if (++count > 120) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getAddress is giving up for " + pId);
break;
}
// Just wait a bit
waitABit();
}
return null;
}
/**
* Given a list of addresses, find the fastest reachable address.
*
* The address returned must be pingable.<BR>
* We prefer an address whose protocol is, in order:<BR>
* <ol>
* <li>connected and fast.
* <li>connected and slow.
* <li>unconnected and fast.
* <li>unconnected and slow
* </ol>
*
* @param addrs A list of addresses to evaulate reachability.
*/
public EndpointAddress getBestLocalRoute(Enumeration addrs) {
//todo: Evaluate why peer is an arg. Remove it if not needed.
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getBestLocalRoute:");
EndpointProtocol proto = null;
EndpointAddress addr = null;
EndpointAddress bestAddr = null;
String protoName = null;
boolean direct = false;
boolean fast = false;
while (addrs.hasMoreElements()) {
try {
addr = (EndpointAddress) addrs.nextElement();
protoName = addr.getProtocolName();
// Ignore ourselves
if (protoName.equals(getProtocolName())) continue;
proto = endpoint.getEndpointProtocolByName(protoName);
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("getBestLocalRoute trying: " + addr.toString()
+ " on protocol " + proto.getProtocolName());
if (proto == null) {
continue;
}
if (!proto.allowRouting()) {
// This protocol should not be used for routing.
continue;
}
if (!proto.ping(addr)) {
// This protocol cannot reach the target addr
continue;
}
if (bestAddr == null) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("Found: " + addr.toString());
bestAddr = addr;
}
if (proto.isConnectionOriented()) {
if (direct) {
// There is already a protocol supporting
// a direct connection to the target addr.
if (isFast (proto)) {
return addr;
}
continue;
} else {
direct = true;
if (isFast (proto)) {
return addr;
} else {
bestAddr = addr;
continue;
}
}
} else {
if (direct) {
continue;
} else {
bestAddr = addr;
continue;
}
}
} catch (Exception e) {
// That address is somehow broken.
// Cache that result for a while (5 minutes).
triedAndFailed.put(addr,
new Long(System.currentTimeMillis()));
continue;
}
}
return bestAddr;
}
boolean isFast (EndpointProtocol p) {
String name = p.getProtocolName ();
//PDA requirement 18.02.2002
// beepcore protocol is not present on a PDA for the time being
// return name.equals ("tcp") || name.equals ("beep");
//PDA requirement 18.02.2002
return name.equals ("tcp");
}
/**
* Returns true if the target address is reachable. Otherwise
* returns false.
*/
public boolean ping (EndpointAddress addr) {
try {
return (getAddress(addr.getProtocolName() + "://"
+ addr.getProtocolAddress()) != null);
} catch (Exception e) {
return false;
}
}
public synchronized boolean isLocalRoute(String pId) {
if (directRoutes.containsKey(pId)) {
return true;
}
return false;
}
public synchronized EndpointAddress getLocalRoute(String pId) {
return (EndpointAddress)directRoutes.get(pId);
}
// Adds a new local route only if it is new. Takes care
// of deleting a remote route etc. Returns true if the route was added.
private synchronized void learnLocalRouteSync(String pId,
EndpointAddress addr) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("learnLocalRoute:");
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug(" peerId = " + pId);
try {
directRoutes.put(pId, addr.clone());
} catch (Exception e) {
return; // Failed. Keep things as they were.
}
try {
// If we had a long route, remove it
routedRoutes.remove(pId);
} catch(Exception e2) {
// Fine.
}
notifyAll(); // Tell all those that may be waiting for a route
return;
}
// Adds a new local route only if it is new. Takes care
// of deleting a remote route, etc.
public void learnLocalRoute(String pId) {
// Here we're not synchronized, so this is a hint.
// If later we decide to add this address and it has been already by
// another thread it will not do any damage. But we're about to do a big
// task possibly, so we want to make sure it's not for nothing.
// That's why this test is important here, and not in the synchronized
// method.
if (directRoutes.containsKey(pId)) return; // nothing new.
// We presume that we are able to directly talk to this peer and we weren't
// before. This has do be checked.
EndpointAddress addr = checkPeer (pId);
if (addr == null) {
// No local route
return;
}
learnLocalRouteSync(pId, addr);
}
public synchronized void removeLocalRoute(String pId) {
try {
directRoutes.remove(pId);
} catch (Exception e) {
}
}
// We could be given the address and remove it from our hash table, but unfortunately
// our hashtable is in the other direction and so it is much less expensive to
// start from the destination peer and find-out if the bad direct route is to that peer
// or to the first hop on a long route.
private void brokenRoute(String peer) {
if (isLocalRoute(peer)) {
removeLocalRoute(peer);
return;
}
// Otherwise, look for a long route.
Route route = getRoute(peer);
if (route != null) {
removeLocalRoute(route.router);
removeRoute(peer);
}
}
public synchronized boolean isRoute(String pId) {
return routedRoutes.get(pId) != null;
}
public synchronized Route getRoute(String pId) {
return (Route) routedRoutes.get(pId);
}
// Check if a route is valid.
// Currentely, only loops are detected.
private boolean checkRoute (Route r) {
if (r == null) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("route is null");
return false;
}
if ((r.gateways == null) || (r.gateways.size() == 0)) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("route is empty");
return false;
}
if (r.gateways.contains (localPeerAddr)) {
// The route does contain this local peer. Using this route
// would create a loop. Discard.
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("route contains this peer - loopback");
return false;
}
// Now check for any other potential loops.
Vector peers = new Vector();
for (int i=0; i < r.gateways.size(); ++i) {
try {
if (peers.contains ((String) r.gateways.elementAt (i))) {
// This is a loop.
return false;
} else {
//PDA requirement 18.02.2002
// Vector.add -> Vector.addElement
// peers.add (r.gateways.elementAt(i));
peers.addElement (r.gateways.elementAt(i));
}
} catch (Exception ez1) {
// Not much we can do here
if (LOG.isEnabledFor(Priority.WARN)) LOG.warn ("Exception while processing route checking: " + ez1);
return false;
}
}
// Seems to be a potential good route.
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("route is ok");
return true;
}
// Adds a new long route provided there not a direct one already.
// Replaces any longer route.
// return true if the route was truely new.
private synchronized boolean setRoute(Route r) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("setRoute:");
if (r == null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -