diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
index dcefa84e3..657039400 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
@@ -33,7 +33,8 @@ public class ConfigRestartBean {
ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
//ctx.router().shutdown(Router.EXIT_HARD); // never returns
ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond
- } else if ("cancelShutdown".equals(action) || _("Cancel shutdown", ctx).equals(action)) {
+ } else if ("cancelShutdown".equals(action) || _("Cancel shutdown", ctx).equals(action) ||
+ _("Cancel restart", ctx).equals(action)) {
ctx.router().cancelGracefulShutdown();
} else if ("restartImmediate".equals(action) || _("Restart immediately", ctx).equals(action)) {
ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java
index bac8d0009..fffdcad6a 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java
@@ -37,6 +37,7 @@ public class ConfigUIHelper extends HelperBase {
}
private static final String langs[] = {"de", "en", "fr", "nl", "se", "zh"};
+ private static final String flags[] = {"de", "us", "fr", "nl", "se", "cn"};
private static final String xlangs[] = {_x("German"), _x("English"), _x("French"),
_x("Dutch"), _x("Swedish"), _x("Chinese")};
@@ -49,7 +50,9 @@ public class ConfigUIHelper extends HelperBase {
buf.append(" ").append(_(xlangs[i])).append(" \n");
+ buf.append("value=\"").append(langs[i]).append("\">")
+ .append(" ")
+ .append(_(xlangs[i])).append(" \n");
}
return buf.toString();
}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java
index abd20b770..e551b15f0 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java
@@ -84,8 +84,8 @@ public class NetDbRenderer {
public void renderLeaseSetHTML(Writer out) throws IOException {
StringBuilder buf = new StringBuilder(4*1024);
buf.append("
" + _("Network Database Contents") + " \n");
- buf.append("" + _("View") + " RouterInfo ");
- buf.append("LeaseSets \n");
+ buf.append("" + _("View RouterInfo") + " ");
+ buf.append("").append(_("LeaseSets")).append(" \n");
Set leases = new TreeSet(new LeaseSetComparator());
leases.addAll(_context.netDb().getLeases());
long now = _context.clock().now();
@@ -132,7 +132,7 @@ public class NetDbRenderer {
}
public void renderStatusHTML(Writer out, boolean full) throws IOException {
- out.write("\n");
+ out.write("\n");
if (!_context.netDb().isInitialized()) {
out.write(_("Not initialized"));
out.flush();
@@ -244,7 +244,7 @@ public class NetDbRenderer {
}
for (Iterator iter = info.getAddresses().iterator(); iter.hasNext(); ) {
RouterAddress addr = (RouterAddress)iter.next();
- buf.append(DataHelper.stripHTML(addr.getTransportStyle())).append(": ");
+ buf.append("").append(DataHelper.stripHTML(addr.getTransportStyle())).append(" : ");
for (Iterator optIter = addr.getOptions().keySet().iterator(); optIter.hasNext(); ) {
String name = (String)optIter.next();
String val = addr.getOptions().getProperty(name);
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java
index 090219d50..f7cb64a0a 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java
@@ -105,6 +105,9 @@ class ProfileOrganizerRenderer {
buf.append("");
buf.append(_context.commSystem().renderPeerHTML(peer));
+ // debug
+ //if(prof.getIsExpandedDB())
+ // buf.append(" ** ");
buf.append(" ");
switch (tier) {
@@ -145,18 +148,19 @@ class ProfileOrganizerRenderer {
buf.append(" ").append(num(prof.getIntegrationValue()));
buf.append(" ");
if (_context.shitlist().isShitlisted(peer)) buf.append(_("Banned"));
- if (prof.getIsFailing()) buf.append(" ").append(_("Failing"));
- if (_context.commSystem().wasUnreachable(peer)) buf.append(" ").append(_("Unreachable"));
+ if (prof.getIsFailing()) buf.append(' ').append(_("Failing"));
+ if (_context.commSystem().wasUnreachable(peer)) buf.append(' ').append(_("Unreachable"));
Rate failed = prof.getTunnelHistory().getFailedRate().getRate(30*60*1000);
long fails = failed.getCurrentEventCount() + failed.getLastEventCount();
if (fails > 0) {
Rate accepted = prof.getTunnelCreateResponseTime().getRate(30*60*1000);
long total = fails + accepted.getCurrentEventCount() + accepted.getLastEventCount();
if (total / fails <= 10) // hide if < 10%
- buf.append(' ').append(fails).append('/').append(total).append(" ").append(_("Test Fails"));
+ buf.append(' ').append(fails).append('/').append(total).append(' ').append(_("Test Fails"));
}
buf.append(" ");
- buf.append("profile ");
+ buf.append("").append(_("profile")).append(" ");
buf.append(" +- \n");
buf.append(" ");
// let's not build the whole page in memory (~500 bytes per peer)
@@ -223,14 +227,20 @@ class ProfileOrganizerRenderer {
buf.append("").append(dbh.getUnpromptedDbStoreOld()).append(" ");
buf.append("").append(davg(dbh, 60*60*1000l)).append(" ");
buf.append("").append(davg(dbh, 24*60*60*1000l)).append(" ");
+ } else {
+ for (int i = 0; i < 6; i++)
+ buf.append("").append(_(NA));
}
}
buf.append("");
buf.append("").append(_("Thresholds:")).append(" ");
- buf.append("").append(_("Speed")).append(": ").append(num(_organizer.getSpeedThreshold())).append(" (").append(fast).append(" fast peers) ");
- buf.append("").append(_("Capacity")).append(": ").append(num(_organizer.getCapacityThreshold())).append(" (").append(reliable).append(" high capacity peers) ");
- buf.append("").append(_("Integration")).append(": ").append(num(_organizer.getIntegrationThreshold())).append(" (").append(integrated).append(" well integrated peers)
");
+ buf.append("").append(_("Speed")).append(": ").append(num(_organizer.getSpeedThreshold()))
+ .append(" (").append(fast).append(' ').append(_("fast peers")).append(") ");
+ buf.append("").append(_("Capacity")).append(": ").append(num(_organizer.getCapacityThreshold()))
+ .append(" (").append(reliable).append(' ').append(_("high capacity peers")).append(") ");
+ buf.append("").append(_("Integration")).append(": ").append(num(_organizer.getIntegrationThreshold()))
+ .append(" (").append(integrated).append(' ').append(_(" well integrated peers")).append(")
");
buf.append("").append(_("Definitions")).append(": ");
buf.append("").append(_("groups")).append(" : ").append(_("as determined by the profile organizer")).append(" ");
buf.append("").append(_("caps")).append(" : ").append(_("capabilities in the netDb, not used to determine profiles")).append(" ");
@@ -295,29 +305,29 @@ class ProfileOrganizerRenderer {
private final static DecimalFormat _fmt = new DecimalFormat("###,##0.00");
private final static String num(double num) { synchronized (_fmt) { return _fmt.format(num); } }
- private final static String na = "n/a";
+ private final static String NA = HelperBase._x("n/a");
- private static String avg (PeerProfile prof, long rate) {
+ private String avg (PeerProfile prof, long rate) {
RateStat rs = prof.getDbResponseTime();
if (rs == null)
- return na;
+ return _(NA);
Rate r = rs.getRate(rate);
if (r == null)
- return na;
+ return _(NA);
long c = r.getCurrentEventCount() + r.getLastEventCount();
if (c == 0)
- return na;
+ return _(NA);
double d = r.getCurrentTotalValue() + r.getLastTotalValue();
return Math.round(d/c) + "ms";
}
- private static String davg (DBHistory dbh, long rate) {
+ private String davg (DBHistory dbh, long rate) {
RateStat rs = dbh.getFailedLookupRate();
if (rs == null)
- return na;
+ return _(NA);
Rate r = rs.getRate(rate);
if (r == null)
- return na;
+ return _(NA);
long c = r.getCurrentEventCount() + r.getLastEventCount();
return "" + c;
}
diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp
index 92975a02e..1013653c1 100644
--- a/apps/routerconsole/jsp/config.jsp
+++ b/apps/routerconsole/jsp/config.jsp
@@ -104,7 +104,7 @@
" />
<% String[] ips = nethelper.getAddresses();
if (ips.length > 0) {
- out.print(" " + intl._("or") + " "+intl._("Select Interface")+" \n");
+ out.print(intl._("or") + " "+intl._("Select Interface")+" \n");
for (int i = 0; i < ips.length; i++) {
out.print("
" /> " />
- <%=intl._("While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port (generally 8887) is forwarded for both UDP and TCP.")%>
+ <%=intl._("While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port is forwarded for both UDP and TCP.")%>
<%=intl._("If you can, please poke a hole in your firewall to allow unsolicited UDP and TCP packets to reach you.")%>
<%=intl._("If you can't, I2P supports UPnP (Universal Plug and Play) and UDP hole punching with \"SSU introductions\" to relay traffic.")%>
@@ -187,7 +187,7 @@
<%=intl._("When in doubt, leave the settings at the defaults.")%>
- <%=intl._("While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port (generally 8887) is forwarded for both UDP and TCP.")%>
+ <%=intl._("While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port is forwarded for both UDP and TCP.")%>
<%=intl._("If you think you have opened up your firewall and I2P still thinks you are firewalled, remember that you may have multiple firewalls, for example both software packages and external hardware routers.")%>
<%=intl._("If there is an error, the logs may also help diagnose the problem.")%>
@@ -196,7 +196,7 @@
<%=intl._("Firewalled")%> -
<%=intl._("Your UDP port appears to be firewalled.")%>
<%=intl._("As the firewall detection methods are not 100% reliable, this may occasionally be displayed in error.")%>
- <%=intl._("However, if it appears consistently, you should check whether both your external and internal firewalls are open on port 8887.")%>
+ <%=intl._("However, if it appears consistently, you should check whether both your external and internal firewalls are open for your port.")%>
<%=intl._("I2P will work fine when firewalled, there is no reason for concern. When firewalled, the router uses \"introducers\" to relay inbound connections.")%>
<%=intl._("However, you will get more participating traffic and help the network more if you can open your firewall(s).")%>
<%=intl._("If you think you have already done so, remember that you may have both a hardware and a software firewall, or be behind an additional, institutional firewall you cannot control.")%>
@@ -230,7 +230,7 @@
<%=intl._("I2P does not work well behind this type of firewall. You will probably not be able to accept inbound connections, which will limit your participation in the network.")%>
<%=intl._("ERR - UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart")%> -
<%=intl._("I2P was unable to bind to port 8887 or other configured port.")%>
- <%=intl._("Check to see if another program is using port 8887. If so, stop that program or configure I2P to use a different port.")%>
+ <%=intl._("Check to see if another program is using the configured port. If so, stop that program or configure I2P to use a different port.")%>
<%=intl._("This may be a transient error, if the other program is no longer using the port.")%>
<%=intl._("However, a restart is always required after this error.")%>
<%=intl._("ERR - UDP Disabled and Inbound TCP host/port not set")%> -
diff --git a/build.xml b/build.xml
index 9d7f55c1b..d065d0655 100644
--- a/build.xml
+++ b/build.xml
@@ -291,7 +291,8 @@
-
+
+
@@ -351,7 +352,7 @@
-
+
@@ -398,7 +399,8 @@
-
+
+
@@ -574,9 +576,9 @@
-
+
-
+
diff --git a/initialNews.xml b/installer/resources/initialNews.xml
similarity index 78%
rename from initialNews.xml
rename to installer/resources/initialNews.xml
index 40892c28d..35800d7d5 100644
--- a/initialNews.xml
+++ b/installer/resources/initialNews.xml
@@ -11,10 +11,6 @@ While you are waiting, please adjust your bandwidth settings on the
configuration page .
-If you can, open up port 8887 on your firewall, then enable inbound TCP on the
-configuration page .
-
-
Once you have a "shared clients" destination listed on the left,
please check out our
FAQ .
@@ -35,9 +31,6 @@ Passe bitte In der Wartezeit deine Einstellungen zur Bandbreite auf der
Einstellungsseite an.
-Bitte öffne sobald möglich den Port 8887 in deiner Firewall, aktiviere danach den eingehenden TCP Verkehr auf der Einstellungsseite .
-
-
Sobald auf der linken Seite eine "shared clients" Verbindung aufgelistet ist besuche bitte unsere FAQ .
diff --git a/news.xml b/installer/resources/news.xml
similarity index 100%
rename from news.xml
rename to installer/resources/news.xml
diff --git a/readme.html b/installer/resources/readme/readme.html
similarity index 100%
rename from readme.html
rename to installer/resources/readme/readme.html
diff --git a/readme_de.html b/installer/resources/readme/readme_de.html
similarity index 100%
rename from readme_de.html
rename to installer/resources/readme/readme_de.html
diff --git a/readme_fr.html b/installer/resources/readme/readme_fr.html
similarity index 100%
rename from readme_fr.html
rename to installer/resources/readme/readme_fr.html
diff --git a/readme_nl.html b/installer/resources/readme/readme_nl.html
similarity index 100%
rename from readme_nl.html
rename to installer/resources/readme/readme_nl.html
diff --git a/readme_sv.html b/installer/resources/readme/readme_sv.html
similarity index 100%
rename from readme_sv.html
rename to installer/resources/readme/readme_sv.html
diff --git a/readme_zh.html b/installer/resources/readme/readme_zh.html
similarity index 100%
rename from readme_zh.html
rename to installer/resources/readme/readme_zh.html
diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java
index 228c216f1..00adcda78 100644
--- a/router/java/src/net/i2p/router/RouterThrottleImpl.java
+++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java
@@ -34,7 +34,7 @@ class RouterThrottleImpl implements RouterThrottle {
private static final int DEFAULT_MAX_TUNNELS = 2500;
private static final String PROP_DEFAULT_KBPS_THROTTLE = "router.defaultKBpsThrottle";
private static final String PROP_MAX_PROCESSINGTIME = "router.defaultProcessingTimeThrottle";
- private static final int DEFAULT_MAX_PROCESSINGTIME = 1500;
+ private static final int DEFAULT_MAX_PROCESSINGTIME = 1250;
/** tunnel acceptance */
public static final int TUNNEL_ACCEPT = 0;
@@ -137,7 +137,7 @@ class RouterThrottleImpl implements RouterThrottle {
_log.warn("Refusing tunnel request due to sendProcessingTime of " + avgSendProcessingTime
+ " ms over the last two minutes, which is too much.");
}
- setTunnelStatus("Rejecting tunnels: congestion");
+ setTunnelStatus("Rejecting tunnels: High message delay");
return TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}
}
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 6c55e1f99..f7ecf8292 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -659,7 +659,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
long now = _context.clock().now();
boolean upLongEnough = _context.router().getUptime() > 60*60*1000;
- // Once we're over 150 routers, reduce the expiration time down from the default,
+ // Once we're over 120 routers, reduce the expiration time down from the default,
// as a crude way of limiting memory usage.
// i.e. at 300 routers the expiration time will be about half the default, etc.
// And if we're floodfill, we can keep the expiration really short, since
@@ -673,7 +673,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
// _kb.size() includes leasesets but that's ok
adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION,
ROUTER_INFO_EXPIRATION_MIN +
- ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 150 / (_kb.size() + 1)));
+ ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 120 / (_kb.size() + 1)));
if (!key.equals(routerInfo.getIdentity().getHash())) {
if (_log.shouldLog(Log.WARN))
@@ -891,12 +891,13 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
public int getPeerTimeout(Hash peer) {
PeerProfile prof = _context.profileOrganizer().getProfile(peer);
double responseTime = MAX_PER_PEER_TIMEOUT;
- if (prof != null)
+ if (prof != null && prof.getIsExpandedDB()) {
responseTime = prof.getDbResponseTime().getLifetimeAverageValue();
- if (responseTime < MIN_PER_PEER_TIMEOUT)
- responseTime = MIN_PER_PEER_TIMEOUT;
- else if (responseTime > MAX_PER_PEER_TIMEOUT)
- responseTime = MAX_PER_PEER_TIMEOUT;
+ if (responseTime < MIN_PER_PEER_TIMEOUT)
+ responseTime = MIN_PER_PEER_TIMEOUT;
+ else if (responseTime > MAX_PER_PEER_TIMEOUT)
+ responseTime = MAX_PER_PEER_TIMEOUT;
+ }
return 4 * (int)responseTime; // give it up to 4x the average response time
}
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
index af3ba2b27..ce8dee193 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
@@ -174,11 +174,13 @@ class StoreJob extends JobImpl {
_state.addSkipped(peer);
} else {
int peerTimeout = _facade.getPeerTimeout(peer);
- PeerProfile prof = getContext().profileOrganizer().getProfile(peer);
- if (prof != null) {
- RateStat failing = prof.getDBHistory().getFailedLookupRate();
- Rate failed = failing.getRate(60*60*1000);
- }
+
+ //PeerProfile prof = getContext().profileOrganizer().getProfile(peer);
+ //if (prof != null && prof.getIsExpandedDB()) {
+ // RateStat failing = prof.getDBHistory().getFailedLookupRate();
+ // Rate failed = failing.getRate(60*60*1000);
+ //}
+
//long failedCount = failed.getCurrentEventCount()+failed.getLastEventCount();
//if (failedCount > 10) {
// _state.addSkipped(peer);
diff --git a/router/java/src/net/i2p/router/peermanager/IntegrationCalculator.java b/router/java/src/net/i2p/router/peermanager/IntegrationCalculator.java
index 7fdc5fbce..f306b1995 100644
--- a/router/java/src/net/i2p/router/peermanager/IntegrationCalculator.java
+++ b/router/java/src/net/i2p/router/peermanager/IntegrationCalculator.java
@@ -19,12 +19,15 @@ public class IntegrationCalculator extends Calculator {
@Override
public double calc(PeerProfile profile) {
- // give more weight to recent counts
- long val = profile.getDbIntroduction().getRate(24*60*60*1000l).getCurrentEventCount();
- val += 2 * 4 * profile.getDbIntroduction().getRate(6*60*60*1000l).getLastEventCount();
- val += 3 * 4 * profile.getDbIntroduction().getRate(6*60*60*1000l).getCurrentEventCount();
- val += 4 * 24 * profile.getDbIntroduction().getRate(60*60*1000l).getCurrentEventCount();
- val /= 10;
+ long val = 0;
+ if (profile.getIsExpandedDB()) {
+ // give more weight to recent counts
+ val = profile.getDbIntroduction().getRate(24*60*60*1000l).getCurrentEventCount();
+ val += 2 * 4 * profile.getDbIntroduction().getRate(6*60*60*1000l).getLastEventCount();
+ val += 3 * 4 * profile.getDbIntroduction().getRate(6*60*60*1000l).getCurrentEventCount();
+ val += 4 * 24 * profile.getDbIntroduction().getRate(60*60*1000l).getCurrentEventCount();
+ val /= 10;
+ }
val += profile.getIntegrationBonus();
return val;
}
diff --git a/router/java/src/net/i2p/router/peermanager/PeerProfile.java b/router/java/src/net/i2p/router/peermanager/PeerProfile.java
index 5a5d51eed..a0e4f76a0 100644
--- a/router/java/src/net/i2p/router/peermanager/PeerProfile.java
+++ b/router/java/src/net/i2p/router/peermanager/PeerProfile.java
@@ -36,8 +36,8 @@ public class PeerProfile {
private long _lastHeardFrom;
private double _tunnelTestResponseTimeAvg;
// periodic rates
- private RateStat _sendSuccessSize = null;
- private RateStat _receiveSize = null;
+ //private RateStat _sendSuccessSize = null;
+ //private RateStat _receiveSize = null;
private RateStat _dbResponseTime = null;
private RateStat _tunnelCreateResponseTime = null;
private RateStat _tunnelTestResponseTime = null;
@@ -56,6 +56,7 @@ public class PeerProfile {
private DBHistory _dbHistory;
// does this peer profile contain expanded data, or just the basics?
private boolean _expanded;
+ private boolean _expandedDB;
private int _consecutiveShitlists;
public PeerProfile(RouterContext context, Hash peer) {
@@ -72,6 +73,8 @@ public class PeerProfile {
_consecutiveShitlists = 0;
_tunnelTestResponseTimeAvg = 0.0d;
_peer = peer;
+ // this is always true, and there are several places in the router that will NPE
+ // if it is false, so all need to be fixed before we can have non-expanded profiles
if (expand)
expandProfile();
}
@@ -87,6 +90,7 @@ public class PeerProfile {
*
*/
public boolean getIsExpanded() { return _expanded; }
+ public boolean getIsExpandedDB() { return _expandedDB; }
public int incrementShitlists() { return _consecutiveShitlists++; }
public void unshitlist() { _consecutiveShitlists = 0; }
@@ -107,18 +111,25 @@ public class PeerProfile {
*
* Note: this appears to be the only use for these two RateStats.
*
+ * Update: Rewritten so we can get rid of the two RateStats.
+ * This also helps by not having it depend on coalesce boundaries.
+ *
* @param period must be one of the periods in the RateStat constructors below
* (5*60*1000 or 60*60*1000)
*/
public boolean getIsActive(long period) {
- if ( (getSendSuccessSize().getRate(period).getCurrentEventCount() > 0) ||
- (getSendSuccessSize().getRate(period).getLastEventCount() > 0) ||
- (getReceiveSize().getRate(period).getCurrentEventCount() > 0) ||
- (getReceiveSize().getRate(period).getLastEventCount() > 0) ||
- _context.commSystem().isEstablished(_peer) )
- return true;
- else
- return false;
+ //if ( (getSendSuccessSize().getRate(period).getCurrentEventCount() > 0) ||
+ // (getSendSuccessSize().getRate(period).getLastEventCount() > 0) ||
+ // (getReceiveSize().getRate(period).getCurrentEventCount() > 0) ||
+ // (getReceiveSize().getRate(period).getLastEventCount() > 0) ||
+ // _context.commSystem().isEstablished(_peer) )
+ // return true;
+ //else
+ // return false;
+ long before = _context.clock().now() - period;
+ return getLastHeardFrom() < before ||
+ getLastSendSuccessful() < before ||
+ _context.commSystem().isEstablished(_peer);
}
@@ -142,25 +153,31 @@ public class PeerProfile {
public long getLastHeardFrom() { return _lastHeardFrom; }
public void setLastHeardFrom(long when) { _lastHeardFrom = when; }
- /** history of tunnel activity with the peer */
+ /** history of tunnel activity with the peer
+ Warning - may return null if !getIsExpanded() */
public TunnelHistory getTunnelHistory() { return _tunnelHistory; }
public void setTunnelHistory(TunnelHistory history) { _tunnelHistory = history; }
- /** history of db activity with the peer */
+ /** history of db activity with the peer
+ Warning - may return null if !getIsExpandedDB() */
public DBHistory getDBHistory() { return _dbHistory; }
public void setDBHistory(DBHistory hist) { _dbHistory = hist; }
/** how large successfully sent messages are, calculated over a 1 minute, 1 hour, and 1 day period */
- public RateStat getSendSuccessSize() { return _sendSuccessSize; }
+ //public RateStat getSendSuccessSize() { return _sendSuccessSize; }
/** how large received messages are, calculated over a 1 minute, 1 hour, and 1 day period */
- public RateStat getReceiveSize() { return _receiveSize; }
- /** how long it takes to get a db response from the peer (in milliseconds), calculated over a 1 minute, 1 hour, and 1 day period */
+ //public RateStat getReceiveSize() { return _receiveSize; }
+ /** how long it takes to get a db response from the peer (in milliseconds), calculated over a 1 minute, 1 hour, and 1 day period
+ Warning - may return null if !getIsExpandedDB() */
public RateStat getDbResponseTime() { return _dbResponseTime; }
- /** how long it takes to get a tunnel create response from the peer (in milliseconds), calculated over a 1 minute, 1 hour, and 1 day period */
+ /** how long it takes to get a tunnel create response from the peer (in milliseconds), calculated over a 1 minute, 1 hour, and 1 day period
+ Warning - may return null if !getIsExpanded() */
public RateStat getTunnelCreateResponseTime() { return _tunnelCreateResponseTime; }
- /** how long it takes to successfully test a tunnel this peer participates in (in milliseconds), calculated over a 10 minute, 1 hour, and 1 day period */
+ /** how long it takes to successfully test a tunnel this peer participates in (in milliseconds), calculated over a 10 minute, 1 hour, and 1 day period
+ Warning - may return null if !getIsExpanded() */
public RateStat getTunnelTestResponseTime() { return _tunnelTestResponseTime; }
- /** how many new peers we get from dbSearchReplyMessages or dbStore messages, calculated over a 1 hour, 1 day, and 1 week period */
+ /** how many new peers we get from dbSearchReplyMessages or dbStore messages, calculated over a 1 hour, 1 day, and 1 week period
+ Warning - may return null if !getIsExpandedDB() */
public RateStat getDbIntroduction() { return _dbIntroduction; }
/**
@@ -327,10 +344,12 @@ public class PeerProfile {
* extensive stats on them, call this to discard excess data points. Specifically,
* this drops the rates, the tunnelHistory, and the dbHistory.
*
+ * UNUSED for now, will cause NPEs elsewhere
*/
+/*****
public void shrinkProfile() {
- _sendSuccessSize = null;
- _receiveSize = null;
+ //_sendSuccessSize = null;
+ //_receiveSize = null;
_dbResponseTime = null;
_tunnelCreateResponseTime = null;
_tunnelTestResponseTime = null;
@@ -339,7 +358,9 @@ public class PeerProfile {
_dbHistory = null;
_expanded = false;
+ _expandedDB = false;
}
+******/
/**
* When the given peer is performing well enough that we want to keep detailed
@@ -350,32 +371,43 @@ public class PeerProfile {
*/
public void expandProfile() {
String group = (null == _peer ? "profileUnknown" : _peer.toBase64().substring(0,6));
- if (_sendSuccessSize == null)
- _sendSuccessSize = new RateStat("sendSuccessSize", "How large successfully sent messages are", group, new long[] { 5*60*1000l, 60*60*1000l });
- if (_receiveSize == null)
- _receiveSize = new RateStat("receiveSize", "How large received messages are", group, new long[] { 5*60*1000l, 60*60*1000l } );
- if (_dbResponseTime == null)
- _dbResponseTime = new RateStat("dbResponseTime", "how long it takes to get a db response from the peer (in milliseconds)", group, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000 } );
+ //if (_sendSuccessSize == null)
+ // _sendSuccessSize = new RateStat("sendSuccessSize", "How large successfully sent messages are", group, new long[] { 5*60*1000l, 60*60*1000l });
+ //if (_receiveSize == null)
+ // _receiveSize = new RateStat("receiveSize", "How large received messages are", group, new long[] { 5*60*1000l, 60*60*1000l } );
if (_tunnelCreateResponseTime == null)
_tunnelCreateResponseTime = new RateStat("tunnelCreateResponseTime", "how long it takes to get a tunnel create response from the peer (in milliseconds)", group, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000 } );
if (_tunnelTestResponseTime == null)
_tunnelTestResponseTime = new RateStat("tunnelTestResponseTime", "how long it takes to successfully test a tunnel this peer participates in (in milliseconds)", group, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000 } );
- if (_dbIntroduction == null)
- _dbIntroduction = new RateStat("dbIntroduction", "how many new peers we get from dbSearchReplyMessages or dbStore messages", group, new long[] { 60*60*1000l, 6*60*60*1000l, 24*60*60*1000l });
if (_tunnelHistory == null)
_tunnelHistory = new TunnelHistory(_context, group);
+
+ //_sendSuccessSize.setStatLog(_context.statManager().getStatLog());
+ //_receiveSize.setStatLog(_context.statManager().getStatLog());
+ _tunnelCreateResponseTime.setStatLog(_context.statManager().getStatLog());
+ _tunnelTestResponseTime.setStatLog(_context.statManager().getStatLog());
+ _expanded = true;
+ }
+
+ /**
+ * For floodfills
+ */
+ public synchronized void expandDBProfile() {
+ String group = (null == _peer ? "profileUnknown" : _peer.toBase64().substring(0,6));
+ if (_dbResponseTime == null)
+ _dbResponseTime = new RateStat("dbResponseTime", "how long it takes to get a db response from the peer (in milliseconds)", group, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000 } );
+ if (_dbIntroduction == null)
+ _dbIntroduction = new RateStat("dbIntroduction", "how many new peers we get from dbSearchReplyMessages or dbStore messages", group, new long[] { 60*60*1000l, 6*60*60*1000l, 24*60*60*1000l });
+
if (_dbHistory == null)
_dbHistory = new DBHistory(_context, group);
- _sendSuccessSize.setStatLog(_context.statManager().getStatLog());
- _receiveSize.setStatLog(_context.statManager().getStatLog());
_dbResponseTime.setStatLog(_context.statManager().getStatLog());
- _tunnelCreateResponseTime.setStatLog(_context.statManager().getStatLog());
- _tunnelTestResponseTime.setStatLog(_context.statManager().getStatLog());
_dbIntroduction.setStatLog(_context.statManager().getStatLog());
- _expanded = true;
+ _expandedDB = true;
}
+
/** once a day, on average, cut the measured throughtput values in half */
/** let's try once an hour times 3/4 */
private static final int DROP_PERIOD_MINUTES = 60;
@@ -419,14 +451,16 @@ public class PeerProfile {
/** update the stats and rates (this should be called once a minute) */
public void coalesceStats() {
if (!_expanded) return;
- _dbIntroduction.coalesceStats();
- _dbResponseTime.coalesceStats();
- _receiveSize.coalesceStats();
- _sendSuccessSize.coalesceStats();
+ //_receiveSize.coalesceStats();
+ //_sendSuccessSize.coalesceStats();
_tunnelCreateResponseTime.coalesceStats();
_tunnelTestResponseTime.coalesceStats();
- _dbHistory.coalesceStats();
_tunnelHistory.coalesceStats();
+ if (_expandedDB) {
+ _dbIntroduction.coalesceStats();
+ _dbResponseTime.coalesceStats();
+ _dbHistory.coalesceStats();
+ }
coalesceThroughput();
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java b/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
index 1c40b003d..5da853c61 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
@@ -39,7 +39,7 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastSendSuccessful(_context.clock().now());
- data.getSendSuccessSize().addData(bytesSent, msToSend);
+ //data.getSendSuccessSize().addData(bytesSent, msToSend);
}
/**
@@ -169,11 +169,14 @@ public class ProfileManagerImpl implements ProfileManager {
/**
* Note that the peer was able to return the valid data for a db lookup
*
+ * This will force creation of DB stats
*/
public void dbLookupSuccessful(Hash peer, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
+ if (!data.getIsExpandedDB())
+ data.expandDBProfile();
data.getDbResponseTime().addData(responseTimeMs, responseTimeMs);
DBHistory hist = data.getDBHistory();
hist.lookupSuccessful();
@@ -183,10 +186,13 @@ public class ProfileManagerImpl implements ProfileManager {
* Note that the peer was unable to reply to a db lookup - either with data or with
* a lookupReply redirecting the user elsewhere
*
+ * This will force creation of DB stats
*/
public void dbLookupFailed(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
+ if (!data.getIsExpandedDB())
+ data.expandDBProfile();
DBHistory hist = data.getDBHistory();
hist.lookupFailed();
}
@@ -203,6 +209,8 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
+ if (!data.getIsExpandedDB())
+ return;
data.getDbResponseTime().addData(responseTimeMs, responseTimeMs);
data.getDbIntroduction().addData(newPeers, responseTimeMs);
DBHistory hist = data.getDBHistory();
@@ -217,6 +225,8 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
+ if (!data.getIsExpandedDB())
+ return;
DBHistory hist = data.getDBHistory();
hist.lookupReceived();
}
@@ -229,6 +239,8 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
+ if (!data.getIsExpandedDB())
+ return;
DBHistory hist = data.getDBHistory();
hist.unpromptedStoreReceived(wasNewKey);
}
@@ -242,8 +254,10 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
long now = _context.clock().now();
- data.setLastSendSuccessful(now);
data.setLastHeardFrom(now);
+ if (!data.getIsExpandedDB())
+ return;
+ data.setLastSendSuccessful(now);
// we could do things like update some sort of "how many successful stores we've sent them"...
// naah.. dont really care now
}
@@ -279,7 +293,7 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
- data.getReceiveSize().addData(bytesRead, msToReceive);
+ //data.getReceiveSize().addData(bytesRead, msToReceive);
}
private PeerProfile getProfile(Hash peer) {
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index 4fd812efa..20f0fba3d 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -241,7 +241,7 @@ public class ProfileOrganizer {
*/
public boolean peerSendsBadReplies(Hash peer) {
PeerProfile profile = getProfile(peer);
- if (profile != null) {
+ if (profile != null && profile.getIsExpandedDB()) {
RateStat invalidReplyRateStat = profile.getDBHistory().getInvalidReplyRate();
Rate invalidReplyRate = invalidReplyRateStat.getRate(30*60*1000l);
if ( (invalidReplyRate.getCurrentTotalValue() > MAX_BAD_REPLIES_PER_HOUR) ||
diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
index e7151314e..606b4883c 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
@@ -128,18 +128,20 @@ class ProfilePersistenceHelper {
out.write(buf.toString().getBytes());
- profile.getTunnelHistory().store(out);
- profile.getDBHistory().store(out);
-
if (profile.getIsExpanded()) {
// only write out expanded data if, uh, we've got it
- profile.getDbIntroduction().store(out, "dbIntroduction");
- profile.getDbResponseTime().store(out, "dbResponseTime");
- profile.getReceiveSize().store(out, "receiveSize");
- profile.getSendSuccessSize().store(out, "sendSuccessSize");
+ profile.getTunnelHistory().store(out);
+ //profile.getReceiveSize().store(out, "receiveSize");
+ //profile.getSendSuccessSize().store(out, "sendSuccessSize");
profile.getTunnelCreateResponseTime().store(out, "tunnelCreateResponseTime");
profile.getTunnelTestResponseTime().store(out, "tunnelTestResponseTime");
}
+
+ if (profile.getIsExpandedDB()) {
+ profile.getDBHistory().store(out);
+ profile.getDbIntroduction().store(out, "dbIntroduction");
+ profile.getDbResponseTime().store(out, "dbResponseTime");
+ }
}
public Set readProfiles() {
@@ -211,12 +213,22 @@ class ProfilePersistenceHelper {
profile.setPeakTunnel1mThroughputKBps(getDouble(props, "tunnelPeakTunnel1mThroughput"));
profile.getTunnelHistory().load(props);
- profile.getDBHistory().load(props);
-
- profile.getDbIntroduction().load(props, "dbIntroduction", true);
- profile.getDbResponseTime().load(props, "dbResponseTime", true);
- profile.getReceiveSize().load(props, "receiveSize", true);
- profile.getSendSuccessSize().load(props, "sendSuccessSize", true);
+
+ // In the interest of keeping the in-memory profiles small,
+ // don't load the DB info at all unless there is something interesting there
+ // (i.e. floodfills)
+ // It seems like we do one or two lookups as a part of handshaking?
+ // Not sure, to be researched.
+ if (getLong(props, "dbHistory.successfulLookups") > 1 ||
+ getLong(props, "dbHistory.failedlLokups") > 1) {
+ profile.expandDBProfile();
+ profile.getDBHistory().load(props);
+ profile.getDbIntroduction().load(props, "dbIntroduction", true);
+ profile.getDbResponseTime().load(props, "dbResponseTime", true);
+ }
+
+ //profile.getReceiveSize().load(props, "receiveSize", true);
+ //profile.getSendSuccessSize().load(props, "sendSuccessSize", true);
profile.getTunnelCreateResponseTime().load(props, "tunnelCreateResponseTime", true);
profile.getTunnelTestResponseTime().load(props, "tunnelTestResponseTime", true);
diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java
index 6ed11cdc2..0fc538a3f 100644
--- a/router/java/src/net/i2p/router/transport/UPnP.java
+++ b/router/java/src/net/i2p/router/transport/UPnP.java
@@ -636,25 +636,20 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
}
public void run() {
+ HashMap map = new HashMap(1);
for(ForwardPort port : portsToForwardNow) {
String proto = protoToString(port.protocol);
+ map.clear();
+ ForwardPortStatus fps;
if (proto.length() <= 1) {
- HashMap map = new HashMap();
- map.put(port, new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber));
- forwardCallback.portForwardStatus(map);
- continue;
- }
- if(tryAddMapping(proto, port.portNumber, port.name, port)) {
- HashMap map = new HashMap();
- map.put(port, new ForwardPortStatus(ForwardPortStatus.MAYBE_SUCCESS, "Port apparently forwarded by UPnP", port.portNumber));
- forwardCallback.portForwardStatus(map);
- continue;
+ fps = new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber);
+ } else if(tryAddMapping(proto, port.portNumber, port.name, port)) {
+ fps = new ForwardPortStatus(ForwardPortStatus.MAYBE_SUCCESS, "Port apparently forwarded by UPnP", port.portNumber);
} else {
- HashMap map = new HashMap();
- map.put(port, new ForwardPortStatus(ForwardPortStatus.PROBABLE_FAILURE, "UPnP port forwarding apparently failed", port.portNumber));
- forwardCallback.portForwardStatus(map);
- continue;
+ fps = new ForwardPortStatus(ForwardPortStatus.PROBABLE_FAILURE, "UPnP port forwarding apparently failed", port.portNumber);
}
+ map.put(port, fps);
+ forwardCallback.portForwardStatus(map);
}
}
}
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
index f828361e2..cffb8fd8b 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java
@@ -22,7 +22,11 @@ public class UDPEndpoint {
private DatagramSocket _socket;
private InetAddress _bindAddress;
- public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) throws SocketException {
+ /**
+ * @param listenPort -1 or the requested port, may not be honored
+ * @param bindAddress null ok
+ */
+ public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) {
_context = ctx;
_log = ctx.logManager().getLog(UDPEndpoint.class);
_transport = transport;
@@ -30,23 +34,20 @@ public class UDPEndpoint {
_listenPort = listenPort;
}
+ /** caller should call getListenPort() after this to get the actual bound port and determine success */
public void startup() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Starting up the UDP endpoint");
shutdown();
- try {
- if (_bindAddress == null)
- _socket = new DatagramSocket(_listenPort);
- else
- _socket = new DatagramSocket(_listenPort, _bindAddress);
- _sender = new UDPSender(_context, _socket, "UDPSender");
- _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver");
- _sender.startup();
- _receiver.startup();
- } catch (SocketException se) {
- _transport.setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
- _log.log(Log.CRIT, "Unable to bind on port " + _listenPort, se);
+ _socket = getSocket();
+ if (_socket == null) {
+ _log.log(Log.CRIT, "UDP Unable to open a port");
+ return;
}
+ _sender = new UDPSender(_context, _socket, "UDPSender");
+ _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver");
+ _sender.startup();
+ _receiver.startup();
}
public void shutdown() {
@@ -60,6 +61,8 @@ public class UDPEndpoint {
}
public void setListenPort(int newPort) { _listenPort = newPort; }
+
+/*******
public void updateListenPort(int newPort) {
if (newPort == _listenPort) return;
try {
@@ -76,7 +79,54 @@ public class UDPEndpoint {
_log.error("Unable to bind on " + _listenPort);
}
}
+********/
+ /** 8998 is monotone, and 32000 is the wrapper, so let's stay between those */
+ private static final int MIN_RANDOM_PORT = 9111;
+ private static final int MAX_RANDOM_PORT = 31777;
+ private static final int MAX_PORT_RETRIES = 20;
+
+ /**
+ * Open socket using requested port in _listenPort and bind host in _bindAddress.
+ * If _listenPort <= 0, or requested port is busy, repeatedly try a new random port.
+ * @return null on failure
+ * Sets _listenPort to actual port or -1 on failure
+ */
+ private DatagramSocket getSocket() {
+ DatagramSocket socket = null;
+ int port = _listenPort;
+
+ for (int i = 0; i < MAX_PORT_RETRIES; i++) {
+ if (port <= 0) {
+ // try random ports rather than just do new DatagramSocket()
+ // so we stay out of the way of other I2P stuff
+ port = MIN_RANDOM_PORT + _context.random().nextInt(MAX_RANDOM_PORT - MIN_RANDOM_PORT);
+ }
+ try {
+ if (_bindAddress == null)
+ socket = new DatagramSocket(port);
+ else
+ socket = new DatagramSocket(port, _bindAddress);
+ break;
+ } catch (SocketException se) {
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Binding to port " + port + " failed: " + se);
+ }
+ port = -1;
+ }
+ if (socket == null) {
+ _log.log(Log.CRIT, "SSU Unable to bind to a port on " + _bindAddress);
+ } else if (port != _listenPort) {
+ if (_listenPort > 0)
+ _log.error("SSU Unable to bind to requested port " + _listenPort + ", using random port " + port);
+ else
+ _log.error("SSU selected random port " + port);
+ }
+ _listenPort = port;
+ return socket;
+ }
+
+ /** call after startup() to get actual port or -1 on startup failure */
public int getListenPort() { return _listenPort; }
public UDPSender getSender() { return _sender; }
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 2bdf8a466..2556bdb7b 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -100,6 +100,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public static final String STYLE = "SSU";
public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
+ /** now unused, we pick a random port */
public static final int DEFAULT_INTERNAL_PORT = 8887;
/** since fixed port defaults to true, this doesnt do anything at the moment.
* We should have an exception if it matches the existing low port. */
@@ -137,6 +138,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers";
/** do we allow direct SSU connections, sans introducers? */
public static final String PROP_ALLOW_DIRECT = "i2np.udp.allowDirect";
+ /** this is rarely if ever used, default is to bind to wildcard address */
public static final String PROP_BIND_INTERFACE = "i2np.udp.bindInterface";
/** how many relays offered to us will we use at a time? */
@@ -226,40 +228,41 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
System.arraycopy(_context.routerHash().getData(), 0, _introKey.getData(), 0, SessionKey.KEYSIZE_BYTES);
rebuildExternalAddress();
-
- int port = -1;
- if (_externalListenPort <= 0) {
- // no explicit external port, so lets try an internal one
- port = _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT);
- // attempt to use it as our external port - this will be overridden by
- // externalAddressReceived(...)
- _context.router().setConfigSetting(PROP_EXTERNAL_PORT, port+"");
- _context.router().saveConfig();
- } else {
- port = _externalListenPort;
- if (_log.shouldLog(Log.INFO))
- _log.info("Binding to the explicitly specified external port: " + port);
- }
- if (_endpoint == null) {
- String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
- InetAddress bindToAddr = null;
- if (bindTo != null) {
- try {
- bindToAddr = InetAddress.getByName(bindTo);
- } catch (UnknownHostException uhe) {
- if (_log.shouldLog(Log.ERROR))
- _log.error("Invalid SSU bind interface specified [" + bindTo + "]", uhe);
- bindToAddr = null;
- }
- }
+
+ // bind host
+ String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
+ InetAddress bindToAddr = null;
+ if (bindTo != null) {
try {
- _endpoint = new UDPEndpoint(_context, this, port, bindToAddr);
- } catch (SocketException se) {
- if (_log.shouldLog(Log.CRIT))
- _log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se);
+ bindToAddr = InetAddress.getByName(bindTo);
+ } catch (UnknownHostException uhe) {
+ _log.log(Log.CRIT, "Invalid SSU bind interface specified [" + bindTo + "]", uhe);
+ setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
return;
}
+ }
+
+ // Requested bind port
+ // This may be -1 or may not be honored if busy,
+ // we will check below after starting up the endpoint.
+ int port;
+ int oldIPort = _context.getProperty(PROP_INTERNAL_PORT, -1);
+ int oldEPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
+ if (_externalListenPort <= 0) {
+ // no explicit external port, so lets try an internal one
+ if (oldIPort > 0)
+ port = oldIPort;
+ else
+ port = oldEPort;
} else {
+ port = _externalListenPort;
+ }
+ if (_log.shouldLog(Log.INFO))
+ _log.info("Binding to the port: " + port);
+ if (_endpoint == null) {
+ _endpoint = new UDPEndpoint(_context, this, port, bindToAddr);
+ } else {
+ // todo, set bind address too
_endpoint.setListenPort(port);
}
@@ -278,7 +281,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (_flooder == null)
_flooder = new UDPFlooder(_context, this);
+ // Startup the endpoint with the requested port, check the actual port, and
+ // take action if it failed or was different than requested or it needs to be saved
_endpoint.startup();
+ int newPort = _endpoint.getListenPort();
+ _externalListenPort = newPort;
+ if (newPort <= 0) {
+ _log.log(Log.CRIT, "Unable to open UDP port");
+ setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
+ return;
+ }
+ if (newPort != port || newPort != oldIPort || newPort != oldEPort) {
+ // attempt to use it as our external port - this will be overridden by
+ // externalAddressReceived(...)
+ _context.router().setConfigSetting(PROP_INTERNAL_PORT, newPort+"");
+ _context.router().setConfigSetting(PROP_EXTERNAL_PORT, newPort+"");
+ _context.router().saveConfig();
+ }
+
_establisher.startup();
_handler.startup();
_fragments.startup();
@@ -321,11 +341,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public int getLocalPort() { return _externalListenPort; }
public InetAddress getLocalAddress() { return _externalListenHost; }
public int getExternalPort() { return _externalListenPort; }
+
+ /**
+ * _externalListenPort should always be set (by startup()) before this is called,
+ * so the returned value should be > 0
+ */
@Override
public int getRequestedPort() {
if (_externalListenPort > 0)
return _externalListenPort;
- return _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT);
+ return _context.getProperty(PROP_INTERNAL_PORT, -1);
}
/**
@@ -2003,6 +2028,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
buf.append(" ").append(resentTotal);
buf.append(" ").append(dupRecvTotal).append(" \n");
buf.append(" \n");
+
+ /*****
long bytesTransmitted = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes();
// NPE here early
double averagePacketSize = _context.statManager().getRate("udp.sendPacketSize").getLifetimeAverageValue();
@@ -2012,6 +2039,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
double bwResent = (nondupSent <= 0 ? 0d : ((((double)resentTotal)*averagePacketSize) / nondupSent));
buf.append("Percentage of bytes retransmitted (lifetime): ").append(formatPct(bwResent));
buf.append(" (Includes retransmission required by packet loss) \n");
+ *****/
+
out.write(buf.toString());
buf.setLength(0);
out.write(KEY);