propagate from branch 'i2p.i2p.zzz.test' (head be1a2452acf68a8a0137f98f5aeb797055321d6e)

to branch 'i2p.i2p' (head bd6b02d1ae8a99afcea7fdffedf699a6e5c85fbf)
This commit is contained in:
zzz
2009-06-04 16:28:32 +00:00
18 changed files with 164 additions and 99 deletions

View File

@ -75,7 +75,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
private static long __tunnelId = 0;
private long _tunnelId;
private Properties _clientOptions;
private final List _sessions;
private final List<I2PSession> _sessions;
public static final int PACKET_DELAY = 100;
@ -179,7 +179,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
}
}
List getSessions() {
List<I2PSession> getSessions() {
synchronized (_sessions) {
return new ArrayList(_sessions);
}

View File

@ -44,6 +44,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
protected final Object sockLock = new Object(); // Guards sockMgr and mySockets
protected I2PSocketManager sockMgr; // should be final and use a factory. LINT
protected List mySockets = new ArrayList();
protected boolean _ownDest;
protected Destination dest = null;
private int localPort;
@ -114,6 +115,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.l = l;
this.handlerName = handlerName + _clientId;
this.privKeyFile = pkf;
_ownDest = ownDest; // == ! shared client
_context = tunnel.getContext();
@ -129,13 +131,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
boolean openNow = !Boolean.valueOf(tunnel.getClientOptions().getProperty("i2cp.delayOpen")).booleanValue();
if (openNow) {
while (sockMgr == null) {
synchronized (sockLock) {
if (ownDest) {
sockMgr = buildSocketManager();
} else {
sockMgr = getSocketManager();
}
}
verifySocketManager();
if (sockMgr == null) {
_log.log(Log.CRIT, "Unable to create socket manager (our own? " + ownDest + ")");
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
@ -209,27 +205,67 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
}
/**
* Sets the this.sockMgr field if it is null, or if we want a new one
*
* We need a socket manager before getDefaultOptions() and most other things
*/
protected void verifySocketManager() {
synchronized(sockLock) {
boolean newManager = false;
if (this.sockMgr == null) {
newManager = true;
} else {
I2PSession sess = sockMgr.getSession();
if (sess == null) {
newManager = true;
} else if (sess.isClosed() &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
// build a new socket manager and a new dest if the session is closed.
getTunnel().removeSession(sess);
if (_log.shouldLog(Log.WARN))
_log.warn(getTunnel().getClientOptions().getProperty("inbound.nickname") + ": Built a new destination on resume");
newManager = true;
} // else the old socket manager will reconnect the old session if necessary
}
if (newManager) {
if (_ownDest)
this.sockMgr = buildSocketManager();
else
this.sockMgr = getSocketManager();
}
}
}
/** this is ONLY for shared clients */
private static I2PSocketManager socketManager;
/** this is ONLY for shared clients */
protected synchronized I2PSocketManager getSocketManager() {
return getSocketManager(getTunnel(), this.privKeyFile);
}
/** this is ONLY for shared clients */
protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) {
return getSocketManager(tunnel, null);
}
/** this is ONLY for shared clients */
protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
if (socketManager != null) {
I2PSession s = socketManager.getSession();
if ( (s == null) || (s.isClosed()) ) {
_log.info("Building a new socket manager since the old one closed [s=" + s + "]");
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since the old one closed [s=" + s + "]");
if (s != null)
tunnel.removeSession(s);
socketManager = buildSocketManager(tunnel, pkf);
} else {
_log.info("Not building a new socket manager since the old one is open [s=" + s + "]");
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Not building a new socket manager since the old one is open [s=" + s + "]");
}
} else {
_log.info("Building a new socket manager since there is no other one");
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since there is no other one");
socketManager = buildSocketManager(tunnel, pkf);
}
return socketManager;
@ -278,6 +314,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
}
sockManager.setName("Client");
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
tunnel.addSession(sockManager.getSession());
return sockManager;
}
@ -343,12 +381,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
* @return a new I2PSocket
*/
public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
if (sockMgr == null) {
// we need this before getDefaultOptions()
synchronized(sockLock) {
sockMgr = getSocketManager();
}
}
verifySocketManager();
return createI2PSocket(dest, getDefaultOptions());
}
@ -369,22 +402,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
public I2PSocket createI2PSocket(Destination dest, I2PSocketOptions opt) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
I2PSocket i2ps;
if (sockMgr == null) {
// delayed open - call get instead of build because the locking is up there
synchronized(sockLock) {
sockMgr = getSocketManager();
}
} else if (Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
synchronized(sockLock) {
I2PSocketManager oldSockMgr = sockMgr;
// This will build a new socket manager and a new dest if the session is closed.
sockMgr = getSocketManager();
if (oldSockMgr != sockMgr) {
_log.warn("Built a new destination on resume");
}
}
} // else the old socket manager will reconnect the old session if necessary
verifySocketManager();
i2ps = sockMgr.connect(dest, opt);
synchronized (sockLock) {
mySockets.add(i2ps);

View File

@ -157,11 +157,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
if (!defaultOpts.contains("i2p.streaming.inactivityTimeout"))
defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT);
// delayed start
if (sockMgr == null) {
synchronized(sockLock) {
sockMgr = getSocketManager();
}
}
verifySocketManager();
I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);

View File

@ -211,11 +211,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
if (!defaultOpts.contains("i2p.streaming.inactivityTimeout"))
defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT);
// delayed start
if (sockMgr == null) {
synchronized(sockLock) {
sockMgr = getSocketManager();
}
}
verifySocketManager();
I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);

View File

@ -434,6 +434,16 @@ public class TunnelController implements Logging {
public boolean getIsRunning() { return _running; }
public boolean getIsStarting() { return _starting; }
/** if running but no open sessions, we are in standby */
public boolean getIsStandby() {
if (!_running)
return false;
for (I2PSession sess : _tunnel.getSessions()) {
if (!sess.isClosed())
return false;
}
return true;
}
public void getSummary(StringBuffer buf) {
String type = getType();

View File

@ -77,6 +77,7 @@ public class IndexBean {
public static final int RUNNING = 1;
public static final int STARTING = 2;
public static final int NOT_RUNNING = 3;
public static final int STANDBY = 4;
public static final String PROP_TUNNEL_PASSPHRASE = "i2ptunnel.passphrase";
static final String PROP_NONCE = IndexBean.class.getName() + ".nonce";
@ -412,8 +413,12 @@ public class IndexBean {
public int getTunnelStatus(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun == null) return NOT_RUNNING;
if (tun.getIsRunning()) return RUNNING;
else if (tun.getIsStarting()) return STARTING;
if (tun.getIsRunning()) {
if (isClient(tunnel) && tun.getIsStandby())
return STANDBY;
else
return RUNNING;
} else if (tun.getIsStarting()) return STARTING;
else return NOT_RUNNING;
}
@ -778,12 +783,6 @@ public class IndexBean {
config.setProperty("interface", _reachableByOther);
else
config.setProperty("interface", _reachableBy);
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
if (_name != null && !_sharedClient) {
config.setProperty("option.inbound.nickname", _name);
config.setProperty("option.outbound.nickname", _name);
}
config.setProperty("sharedClient", _sharedClient + "");
for (String p : _booleanClientOpts)
config.setProperty("option." + p, "" + _booleanOptions.contains(p));
@ -896,14 +895,12 @@ public class IndexBean {
config.setProperty("option.i2p.streaming.connectDelay", "1000");
else
config.setProperty("option.i2p.streaming.connectDelay", "0");
if (_name != null) {
if ( (!isClient(_type)) || (!_sharedClient) ) {
config.setProperty("option.inbound.nickname", _name);
config.setProperty("option.outbound.nickname", _name);
} else {
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
}
if (isClient(_type) && _sharedClient) {
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
} else if (_name != null) {
config.setProperty("option.inbound.nickname", _name);
config.setProperty("option.outbound.nickname", _name);
}
if ("interactive".equals(_profile))
// This was 1 which doesn't make much sense

View File

@ -97,6 +97,11 @@
case IndexBean.STARTING:
%><div class="statusStarting text">Starting...</div>
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=stop&amp;tunnel=<%=curClient%>">Stop</a>
<%
break;
case IndexBean.STANDBY:
%><div class="statusStarting text">Standby</div>
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=stop&amp;tunnel=<%=curClient%>">Stop</a>
<%
break;
case IndexBean.RUNNING:

View File

@ -91,8 +91,9 @@ public class ReseedHandler {
public boolean isRunning() { return _isRunning; }
public void run() {
_isRunning = true;
System.out.println("Reseed start");
reseed(false);
System.out.println("Reseeding complete");
System.out.println("Reseed complete");
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false");
_isRunning = false;
}
@ -133,7 +134,7 @@ public class ReseedHandler {
}
/**
* Fetch a directory listing and then all the routerInfo files in the listing.
* Fetch a directory listing and then up to 200 routerInfo files in the listing.
* The listing must contain (exactly) strings that match:
* href="routerInfo-{hash}.dat">
* and then it fetches the files
@ -147,6 +148,7 @@ public class ReseedHandler {
try {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage","");
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding: fetching seed URL.");
System.err.println("Reseed from " + seedURL);
URL dir = new URL(seedURL);
byte contentRaw[] = readURL(dir);
if (contentRaw == null) {
@ -160,7 +162,8 @@ public class ReseedHandler {
String content = new String(contentRaw);
Set urls = new HashSet();
int cur = 0;
while (true) {
int total = 0;
while (total++ < 1000) {
int start = content.indexOf("href=\"routerInfo-", cur);
if (start < 0)
break;
@ -170,7 +173,7 @@ public class ReseedHandler {
urls.add(name);
cur = end + 1;
}
if (urls.size() <= 0) {
if (total <= 0) {
_log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed fully (no routerInfo URLs at seed URL). " +
@ -178,13 +181,16 @@ public class ReseedHandler {
return;
}
List urlList = new ArrayList(urls);
Collections.shuffle(urlList);
int fetched = 0;
int errors = 0;
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
// 200 max from one URL
for (Iterator iter = urlList.iterator(); iter.hasNext() && fetched < 200; ) {
try {
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage",
"Reseeding: fetching router info from seed URL (" +
fetched + " successful, " + errors + " errors, " + urls.size() + " total).");
fetched + " successful, " + errors + " errors, " + total + " total).");
fetchSeed(seedURL, (String)iter.next());
fetched++;
@ -197,24 +203,24 @@ public class ReseedHandler {
errors++;
}
}
if (echoStatus) System.out.println();
System.err.println("Reseed got " + fetched + " router infos from " + seedURL);
int failPercent = 100 * errors / urls.size();
int failPercent = 100 * errors / total;
// Less than 10% of failures is considered success,
// because some routerInfos will always fail.
if ((failPercent >= 10) && (failPercent < 90)) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed partly (" + failPercent + "% of " + urls.size() + "). " +
"Last reseed failed partly (" + failPercent + "% of " + total + "). " +
RESEED_TIPS);
}
if (failPercent >= 90) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed (" + failPercent + "% of " + urls.size() + "). " +
"Last reseed failed (" + failPercent + "% of " + total + "). " +
RESEED_TIPS);
}
// Don't go on to the next URL if we have enough
if (fetched > 25)
if (fetched >= 100)
_isRunning = false;
} catch (Throwable t) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",

View File

@ -32,6 +32,7 @@
<input type="submit" name="action" value="Shutdown immediately" />
<input type="submit" name="action" value="Cancel graceful shutdown" />
<% if (System.getProperty("wrapper.version") != null) { %>
<p>If you want the router to restart itself after shutting down, you can choose one of
the following. This is useful in some situations - for example, if you changed
some settings that client applications only read at startup, such as the routerconsole password
@ -41,6 +42,7 @@
<input type="submit" name="action" value="Graceful restart" />
<input type="submit" name="action" value="Hard restart" />
<% } %>
<% if ( (System.getProperty("os.name") != null) && (System.getProperty("os.name").startsWith("Win")) ) { %>
<h4>Systray integration</h4>
@ -61,11 +63,14 @@
down your router immediately. You may want to consider shutting down gracefully, as
above, then running uninstall_i2p_service_winnt.bat.</p>
<% } %>
<% if (System.getProperty("wrapper.version") != null) { %>
<h4>Debugging</h4>
<p>At times, it may be helpful to debug I2P by getting a thread dump. To do so,
please select the following option and review the thread dumped to
<a href="logs.jsp#servicelogs">wrapper.log</a>.</p>
<input type="submit" name="action" value="Dump threads" />
<% } %>
<h4>Launch browser on router startup?</h4>
<p>I2P's main configuration interface is this web console, so for your convenience