diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 8d032f746..5edc79c0c 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -2,7 +2,7 @@
-If you are still having problems, you may want to review the information on the I2P website, post up messages to the I2P discussion forum, or swing by #i2p or -#i2p-chat on IRC at irc.freenode.net, irc.postman.i2p, irc.freshcoffee.i2p or -irc.arcturus.i2p (they're all linked together).
+#i2p-chat on IRC at irc.freenode.net, irc.postman.i2p or irc.freshcoffee.i2p (they're linked together). -As a note, you can change this page by editing the file "docs/readme.html"
\ No newline at end of file +As a note, you can change this page by editing the file "docs/readme.html"
diff --git a/router/java/src/net/i2p/router/PeerManagerFacade.java b/router/java/src/net/i2p/router/PeerManagerFacade.java index c1863c63c..53a4f6bdb 100644 --- a/router/java/src/net/i2p/router/PeerManagerFacade.java +++ b/router/java/src/net/i2p/router/PeerManagerFacade.java @@ -10,6 +10,7 @@ package net.i2p.router; import java.io.Writer; import java.util.List; +import net.i2p.data.Hash; /** * Manage peer references and keep them up to date so that when asked for peers, @@ -25,6 +26,10 @@ public interface PeerManagerFacade extends Service { * @return List of Hash objects of the RouterIdentity for matching peers */ public List selectPeers(PeerSelectionCriteria criteria); + public List getPeersByCapability(char capability); + public void setCapabilities(Hash peer, String caps); + public void removeCapabilities(Hash peer); + public Hash selectRandomByCapability(char capability); } class DummyPeerManagerFacade implements PeerManagerFacade { @@ -33,4 +38,8 @@ class DummyPeerManagerFacade implements PeerManagerFacade { public void restart() {} public void renderStatusHTML(Writer out) { } public List selectPeers(PeerSelectionCriteria criteria) { return null; } + public List getPeersByCapability(char capability) { return null; } + public void setCapabilities(Hash peer, String caps) {} + public void removeCapabilities(Hash peer) {} + public Hash selectRandomByCapability(char capability) { return null; } } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index a3749ec83..1acea8ae1 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -294,6 +294,7 @@ public class Router { ri.setAddresses(_context.commSystem().createAddresses()); if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context)) ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); + addReachabilityCapability(ri); SigningPrivateKey key = _context.keyManager().getSigningPrivateKey(); if (key == null) { _log.log(Log.CRIT, "Internal error - signing private key not known? wtf"); @@ -311,7 +312,31 @@ public class Router { _log.log(Log.CRIT, "Internal error - unable to sign our own address?!", dfe); } } + + public static final char CAPABILITY_REACHABLE = 'R'; + public static final char CAPABILITY_UNREACHABLE = 'U'; + public static final String PROP_FORCE_UNREACHABLE = "router.forceUnreachable"; + public void addReachabilityCapability(RouterInfo ri) { + String forceUnreachable = _context.getProperty(PROP_FORCE_UNREACHABLE); + if ( (forceUnreachable != null) && ("true".equalsIgnoreCase(forceUnreachable)) ) { + ri.addCapability(CAPABILITY_UNREACHABLE); + return; + } + switch (_context.commSystem().getReachabilityStatus()) { + case CommSystemFacade.STATUS_OK: + ri.addCapability(CAPABILITY_REACHABLE); + break; + case CommSystemFacade.STATUS_DIFFERENT: + case CommSystemFacade.STATUS_REJECT_UNSOLICITED: + ri.addCapability(CAPABILITY_UNREACHABLE); + break; + case CommSystemFacade.STATUS_UNKNOWN: + // no explicit capability + break; + } + } + /** * Ugly list of files that we need to kill if we are building a new identity * diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 7ac878557..2d1af5cf6 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.226 $ $Date: 2005/09/02 14:10:06 $"; + public final static String ID = "$Revision: 1.227 $ $Date: 2005/09/04 14:15:49 $"; public final static String VERSION = "0.6.0.5"; - public final static long BUILD = 1; + public final static long BUILD = 2; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java index ae6a96950..6887a9716 100644 --- a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java @@ -9,6 +9,7 @@ package net.i2p.router.networkdb; */ import java.util.Iterator; +import java.util.HashSet; import java.util.Set; import net.i2p.data.DataStructure; @@ -25,6 +26,7 @@ import net.i2p.data.i2np.TunnelGatewayMessage; import net.i2p.router.Job; import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; +import net.i2p.router.Router; import net.i2p.router.TunnelInfo; import net.i2p.router.message.SendMessageDirectJob; import net.i2p.util.Log; @@ -109,11 +111,19 @@ public class HandleDatabaseLookupMessageJob extends JobImpl { } else { RouterInfo info = getContext().netDb().lookupRouterInfoLocally(_message.getSearchKey()); if ( (info != null) && (info.isCurrent(EXPIRE_DELAY)) ) { - // send that routerInfo to the _message.getFromHash peer - if (_log.shouldLog(Log.DEBUG)) - _log.debug("We do have key " + _message.getSearchKey().toBase64() - + " locally as a router info. sending to " + fromKey.toBase64()); - sendData(_message.getSearchKey(), info, fromKey, _message.getReplyTunnel()); + if (isUnreachable(info) && !publishUnreachable()) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Not answering a query for a netDb peer who isn't reachable"); + Set us = new HashSet(1); + us.add(getContext().router().getRouterInfo()); + sendClosest(_message.getSearchKey(), us, fromKey, _message.getReplyTunnel()); + } else { + // send that routerInfo to the _message.getFromHash peer + if (_log.shouldLog(Log.DEBUG)) + _log.debug("We do have key " + _message.getSearchKey().toBase64() + + " locally as a router info. sending to " + fromKey.toBase64()); + sendData(_message.getSearchKey(), info, fromKey, _message.getReplyTunnel()); + } } else { // not found locally - return closest peer routerInfo structs Set routerInfoSet = getContext().netDb().findNearestRouters(_message.getSearchKey(), @@ -127,6 +137,24 @@ public class HandleDatabaseLookupMessageJob extends JobImpl { } } + private boolean isUnreachable(RouterInfo info) { + if (info == null) return true; + String cap = info.getCapabilities(); + if (cap == null) return false; + return cap.indexOf(Router.CAPABILITY_REACHABLE) >= 0; + } + + public static final String PROP_PUBLISH_UNREACHABLE = "router.publishUnreachableRouters"; + public static final boolean DEFAULT_PUBLISH_UNREACHABLE = true; + + private boolean publishUnreachable() { + String publish = getContext().getProperty(PROP_PUBLISH_UNREACHABLE); + if (publish != null) + return Boolean.valueOf(publish).booleanValue(); + else + return DEFAULT_PUBLISH_UNREACHABLE; + } + private boolean weAreClosest(Set routerInfoSet) { boolean weAreClosest = false; for (Iterator iter = routerInfoSet.iterator(); iter.hasNext(); ) { diff --git a/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java b/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java index 41752cfd6..0bfcf8904 100644 --- a/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java +++ b/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java @@ -47,6 +47,7 @@ public class PublishLocalRouterInfoJob extends JobImpl { ri.setAddresses(getContext().commSystem().createAddresses()); if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); + getContext().router().addReachabilityCapability(ri); SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey(); if (key == null) { _log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s"); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java index 295300070..e50a872ab 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java @@ -48,7 +48,7 @@ class FloodfillStoreJob extends StoreJob { _facade = facade; } - protected int getParallelization() { return 2; } + protected int getParallelization() { return 1; } protected int getRedundancy() { return 1; } /** diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index a8fd15367..9499bc1fd 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -688,7 +688,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { _log.info("RouterInfo " + key.toBase64() + " is stored with " + routerInfo.getOptions().size() + " options on " + new Date(routerInfo.getPublished())); - + + _context.peerManager().setCapabilities(key, routerInfo.getCapabilities()); _ds.put(key, routerInfo); synchronized (_lastSent) { if (!_lastSent.containsKey(key)) @@ -721,6 +722,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { return; } + _context.peerManager().removeCapabilities(dbEntry); boolean removed = _kb.remove(dbEntry); if (removed) { if (_log.shouldLog(Log.INFO)) @@ -737,6 +739,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { if (o == null) { boolean removed = _kb.remove(dbEntry); + _context.peerManager().removeCapabilities(dbEntry); // if we dont know the key, lets make sure it isn't a now-dead peer } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java index 460c04aaa..9ee7ae79b 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java @@ -52,7 +52,7 @@ class SearchJob extends JobImpl { private boolean _deferredCleared; private long _startedOn; - private static final int SEARCH_BREDTH = 10; // 10 peers at a time + private static final int SEARCH_BREDTH = 3; // 10 peers at a time private static final int SEARCH_PRIORITY = 400; // large because the search is probably for a real search /** only send the 10 closest "dont tell me about" refs */ static final int MAX_CLOSEST = 10; diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index 9eae72791..97fd03a9f 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -10,11 +10,7 @@ package net.i2p.router.peermanager; import java.io.IOException; import java.io.Writer; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; +import java.util.*; import net.i2p.data.Hash; import net.i2p.router.PeerSelectionCriteria; @@ -30,6 +26,8 @@ class PeerManager { private RouterContext _context; private ProfileOrganizer _organizer; private ProfilePersistenceHelper _persistenceHelper; + private List _peersByCapability[]; + private Map _capabilitiesByPeer; public PeerManager(RouterContext context) { _context = context; @@ -37,6 +35,10 @@ class PeerManager { _persistenceHelper = new ProfilePersistenceHelper(context); _organizer = context.profileOrganizer(); _organizer.setUs(context.routerHash()); + _capabilitiesByPeer = new HashMap(128); + _peersByCapability = new List[26]; + for (int i = 0; i < _peersByCapability.length; i++) + _peersByCapability[i] = new ArrayList(64); loadProfiles(); _context.jobQueue().addJob(new EvaluateProfilesJob(_context)); //_context.jobQueue().addJob(new PersistProfilesJob(_context, this)); @@ -116,6 +118,86 @@ class PeerManager { return new ArrayList(peers); } + public void setCapabilities(Hash peer, String caps) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Setting capabilities for " + peer.toBase64() + " to " + caps); + if (caps != null) caps = caps.toLowerCase(); + synchronized (_capabilitiesByPeer) { + String oldCaps = null; + if (caps != null) + oldCaps = (String)_capabilitiesByPeer.put(peer, caps); + else + oldCaps = (String)_capabilitiesByPeer.remove(peer); + + if (oldCaps != null) { + for (int i = 0; i < oldCaps.length(); i++) { + char c = oldCaps.charAt(i); + if ( (caps == null) || (caps.indexOf(c) < 0) ) { + List peers = locked_getPeers(c); + if (peers != null) + peers.remove(peer); + } + } + } + if (caps != null) { + for (int i = 0; i < caps.length(); i++) { + char c = caps.charAt(i); + if ( (oldCaps != null) && (oldCaps.indexOf(c) >= 0) ) + continue; + List peers = locked_getPeers(c); + if ( (peers != null) && (!peers.contains(peer)) ) + peers.add(peer); + } + } + } + } + + private List locked_getPeers(char c) { + c = Character.toLowerCase(c); + int i = c - 'a'; + if ( (i < 0) || (i >= _peersByCapability.length) ) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Invalid capability " + c + " (" + i + ")"); + return null; + } + return _peersByCapability[i]; + } + + public void removeCapabilities(Hash peer) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Removing capabilities from " + peer.toBase64()); + synchronized (_capabilitiesByPeer) { + String oldCaps = (String)_capabilitiesByPeer.remove(peer); + if (oldCaps != null) { + for (int i = 0; i < oldCaps.length(); i++) { + char c = oldCaps.charAt(i); + List peers = locked_getPeers(c); + if (peers != null) + peers.remove(peer); + } + } + } + } + public Hash selectRandomByCapability(char capability) { + int index = _context.random().nextInt(Integer.MAX_VALUE); + synchronized (_capabilitiesByPeer) { + List peers = locked_getPeers(capability); + if ( (peers != null) && (peers.size() > 0) ) { + index = index % peers.size(); + return (Hash)peers.get(index); + } + } + return null; + } + public List getPeersByCapability(char capability) { + synchronized (_capabilitiesByPeer) { + List peers = locked_getPeers(capability); + if (peers != null) + return new ArrayList(peers); + } + return null; + } + public void renderStatusHTML(Writer out) throws IOException { _organizer.renderStatusHTML(out); } diff --git a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java index 6f89c5a39..305d4d9f4 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java @@ -10,8 +10,10 @@ package net.i2p.router.peermanager; import java.io.IOException; import java.io.Writer; +import java.util.ArrayList; import java.util.List; +import net.i2p.data.Hash; import net.i2p.router.PeerManagerFacade; import net.i2p.router.PeerSelectionCriteria; import net.i2p.router.RouterContext; @@ -57,8 +59,26 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade { public List selectPeers(PeerSelectionCriteria criteria) { return _manager.selectPeers(criteria); } - + + public void setCapabilities(Hash peer, String caps) { + if (_manager == null) return; + _manager.setCapabilities(peer, caps); + } + public void removeCapabilities(Hash peer) { + if (_manager == null) return; + _manager.removeCapabilities(peer); + } + public Hash selectRandomByCapability(char capability) { + if (_manager == null) return null; + return _manager.selectRandomByCapability(capability); + } + public List getPeersByCapability(char capability) { + if (_manager == null) return new ArrayList(0); + return _manager.getPeersByCapability(capability); + } + public void renderStatusHTML(Writer out) throws IOException { _manager.renderStatusHTML(out); } + } diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java index aa17423f8..ec7fc78b3 100644 --- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java @@ -56,6 +56,7 @@ public class CreateRouterInfoJob extends JobImpl { stats.setProperty(RouterInfo.PROP_NETWORK_ID, Router.NETWORK_ID+""); if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); + getContext().router().addReachabilityCapability(info); info.setOptions(stats); info.setPeers(new HashSet()); info.setPublished(getCurrentPublishDate(getContext())); diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java index 16c328adc..decdd9522 100644 --- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java @@ -129,6 +129,7 @@ public class RebuildRouterInfoJob extends JobImpl { info.setOptions(stats); if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); + getContext().router().addReachabilityCapability(info); // info.setPeers(new HashSet()); // this would have the trusted peers info.setPublished(CreateRouterInfoJob.getCurrentPublishDate(getContext())); diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index b13fb2754..4c63f5ec3 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -75,7 +75,10 @@ public class CommSystemFacadeImpl extends CommSystemFacade { return _manager.getMostRecentErrorMessages(); } - public short getReachabilityStatus() { return _manager.getReachabilityStatus(); } + public short getReachabilityStatus() { + if (_manager == null) return CommSystemFacade.STATUS_UNKNOWN; + return _manager.getReachabilityStatus(); + } public void recheckReachability() { _manager.recheckReachability(); } public void renderStatusHTML(Writer out) throws IOException { diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index f8ad0f907..6a13bb095 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -9,14 +9,7 @@ import java.io.Writer; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; +import java.util.*; import net.i2p.data.Base64; import net.i2p.data.DataHelper; @@ -250,7 +243,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _refiller.startup(); _flooder.startup(); _expireEvent.setIsAlive(true); - _testEvent.setIsAlive(true); + _testEvent.setIsAlive(true); // this queues it for 3-6 minutes in the future... + SimpleTimer.getInstance().addEvent(_testEvent, 10*1000); // lets requeue it for Real Soon } public void shutdown() { @@ -832,19 +826,33 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority return active; } + private static class AlphaComparator implements Comparator { + private static final AlphaComparator _instance = new AlphaComparator(); + public static final AlphaComparator instance() { return _instance; } + + public int compare(Object lhs, Object rhs) { + if ( (lhs == null) || (rhs == null) || !(lhs instanceof PeerState) || !(rhs instanceof PeerState)) + throw new IllegalArgumentException("rhs = " + rhs + " lhs = " + lhs); + PeerState l = (PeerState)lhs; + PeerState r = (PeerState)rhs; + // base64 retains binary ordering + return DataHelper.compareTo(l.getRemotePeer().getData(), r.getRemotePeer().getData()); + } + + } public void renderStatusHTML(Writer out) throws IOException { - List peers = null; + TreeSet peers = new TreeSet(AlphaComparator.instance()); synchronized (_peersByIdent) { - peers = new ArrayList(_peersByIdent.values()); + peers.addAll(_peersByIdent.values()); } long offsetTotal = 0; StringBuffer buf = new StringBuffer(512); buf.append("UDP connections: ").append(peers.size()).append("peer | activity (in/out) | "); - buf.append("transfer (in/out) | \n"); - buf.append("uptime | skew | \n"); + buf.append("|||||||||||||||||||||||
peer | idle | "); + buf.append("in/out | \n"); + buf.append("up | skew | \n"); buf.append("cwnd | ssthresh | \n"); buf.append("rtt | dev | rto | \n"); buf.append("send | recv | \n"); @@ -853,42 +861,67 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority out.write(buf.toString()); buf.setLength(0); long now = _context.clock().now(); - for (int i = 0; i < peers.size(); i++) { - PeerState peer = (PeerState)peers.get(i); + for (Iterator iter = peers.iterator(); iter.hasNext(); ) { + PeerState peer = (PeerState)iter.next(); if (now-peer.getLastReceiveTime() > 60*60*1000) continue; // don't include old peers buf.append("||||||||||||||||
"); + buf.append(" | ");
buf.append("");
buf.append(name).append("@");
byte ip[] = peer.getRemoteIP();
for (int j = 0; j < ip.length; j++) {
- buf.append(ip[j] & 0xFF);
+ int num = ip[j] & 0xFF;
+ if (num < 10)
+ buf.append("00");
+ else if (num < 100)
+ buf.append("0");
+ buf.append(num);
if (j + 1 < ip.length)
buf.append('.');
}
- buf.append(':').append(peer.getRemotePort());
+ buf.append(':');
+ int port = peer.getRemotePort();
+ if (port < 10)
+ buf.append("0000");
+ else if (port < 100)
+ buf.append("000");
+ else if (port < 1000)
+ buf.append("00");
+ else if (port < 10000)
+ buf.append("0");
+ buf.append(port);
buf.append("");
- if (_activeThrottle.isChoked(peer.getRemotePeer()))
+ boolean appended = false;
+ if (_activeThrottle.isChoked(peer.getRemotePeer())) {
+ if (!appended) buf.append(" | ");
+ appended = true;
+ }
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append((now-peer.getLastReceiveTime())/1000);
buf.append("s/");
buf.append((now-peer.getLastSendTime())/1000);
- buf.append("s | ");
+ buf.append("s");
- buf.append(""); + buf.append(" | ");
buf.append(formatKBps(peer.getReceiveBps()));
buf.append("KBps/");
buf.append(formatKBps(peer.getSendBps()));
@@ -897,60 +930,60 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
//buf.append("KBps/");
//buf.append(formatKBps(peer.getSendACKBps()));
//buf.append("KBps ");
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(DataHelper.formatDuration(now-peer.getKeyEstablishedTime()));
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getClockSkew()/1000);
- buf.append("s | ");
+ buf.append("s");
offsetTotal = offsetTotal + peer.getClockSkew();
- buf.append(""); + buf.append(" | ");
buf.append(peer.getSendWindowBytes()/1024);
- buf.append("K | ");
+ buf.append("K");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getSlowStartThreshold()/1024);
- buf.append("K | ");
+ buf.append("K");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getRTT());
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getRTTDeviation());
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getRTO());
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getPacketsTransmitted());
- buf.append(" | ");
+ buf.append("");
- buf.append(""); + buf.append(" | ");
buf.append(peer.getPacketsReceived());
- buf.append(" | ");
+ buf.append("");
double sent = (double)peer.getPacketsPeriodTransmitted();
double sendLostPct = 0;
if (sent > 0)
sendLostPct = (double)peer.getPacketsRetransmitted()/(sent);
- buf.append(""); + buf.append(" | ");
//buf.append(formatPct(sendLostPct));
buf.append(peer.getPacketsRetransmitted()); // + "/" + peer.getPacketsPeriodRetransmitted() + "/" + sent);
//buf.append(peer.getPacketRetransmissionRate());
- buf.append(" | ");
+ buf.append("");
double recvDupPct = (double)peer.getPacketsReceivedDuplicate()/(double)peer.getPacketsReceived();
- buf.append(""); + buf.append(" | ");
buf.append(formatPct(recvDupPct));
- buf.append(" | ");
+ buf.append("");
buf.append("