I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit c5fb009c authored by str4d's avatar str4d
Browse files

merge of 'd09201283ea0356bf5b1d3aedc4795a202414930'

     and 'e2f50f8cb50f8593ca882e94cb661c54b87d2468'
parents 4d8973b0 ea2be02a
No related branches found
No related tags found
No related merge requests found
Showing
with 311 additions and 142 deletions
package org.klomp.snark;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
......@@ -393,6 +394,46 @@ public class I2PSnarkUtil {
}
}
/**
* Fetch to memory
* @param retries if < 0, set timeout to a few seconds
* @param initialSize buffer size
* @param maxSize fails if greater
* @return null on error
* @since 0.9.4
*/
public byte[] get(String url, boolean rewrite, int retries, int initialSize, int maxSize) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetching [" + url + "] to memory");
String fetchURL = url;
if (rewrite)
fetchURL = rewriteAnnounce(url);
int timeout;
if (retries < 0) {
if (!connected())
return null;
timeout = EEPGET_CONNECT_TIMEOUT_SHORT;
retries = 0;
} else {
timeout = EEPGET_CONNECT_TIMEOUT;
if (!connected()) {
if (!connect())
return null;
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream(initialSize);
EepGet get = new I2PSocketEepGet(_context, _manager, retries, -1, maxSize, null, out, fetchURL);
if (get.fetch(timeout)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetch successful [" + url + "]: size=" + out.size());
return out.toByteArray();
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Fetch failed [" + url + "]");
return null;
}
}
public I2PServerSocket getServerSocket() {
I2PSocketManager mgr = _manager;
if (mgr != null)
......@@ -523,6 +564,15 @@ public class I2PSnarkUtil {
return Collections.EMPTY_LIST;
return _openTrackers;
}
/**
* List of open trackers to use as backups even if disabled
* @return non-null
* @since 0.9.4
*/
public List<String> getBackupTrackers() {
return _openTrackers;
}
public void setUseOpenTrackers(boolean yes) {
_shouldUseOT = yes;
......
......@@ -20,6 +20,7 @@
package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
......@@ -43,6 +44,7 @@ import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import org.klomp.snark.bencode.InvalidBEncodingException;
import org.klomp.snark.dht.DHT;
/**
......@@ -70,6 +72,8 @@ public class TrackerClient implements Runnable {
private static final String COMPLETED_EVENT = "completed";
private static final String STOPPED_EVENT = "stopped";
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
/** this is our equivalent to router.utorrent.com for bootstrap */
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
private final static int SLEEP = 5; // 5 minutes.
private final static int DELAY_MIN = 2000; // 2 secs.
......@@ -78,7 +82,7 @@ public class TrackerClient implements Runnable {
private final static int INITIAL_SLEEP = 90*1000;
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
private final static long MIN_TRACKER_ANNOUNCE_INTERVAL = 10*60*1000;
private final static long MIN_TRACKER_ANNOUNCE_INTERVAL = 15*60*1000;
private final static long MIN_DHT_ANNOUNCE_INTERVAL = 10*60*1000;
private final I2PSnarkUtil _util;
......@@ -106,6 +110,7 @@ public class TrackerClient implements Runnable {
private volatile boolean _fastUnannounce;
private long lastDHTAnnounce;
private final List<Tracker> trackers;
private final List<Tracker> backupTrackers;
/**
* Call start() to start it.
......@@ -131,6 +136,7 @@ public class TrackerClient implements Runnable {
this.infoHash = urlencode(snark.getInfoHash());
this.peerID = urlencode(snark.getID());
this.trackers = new ArrayList(2);
this.backupTrackers = new ArrayList(2);
}
public synchronized void start() {
......@@ -233,7 +239,7 @@ public class TrackerClient implements Runnable {
if (!_initialized) {
_initialized = true;
// FIXME only when starting everybody at once, not for a single torrent
long delay = I2PAppContext.getGlobalContext().random().nextInt(30*1000);
long delay = _util.getContext().random().nextInt(30*1000);
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {}
......@@ -267,18 +273,20 @@ public class TrackerClient implements Runnable {
if (primary != null) {
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(primary, true));
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
if (_log.shouldLog(Log.WARN))
_log.warn("Skipping invalid or non-i2p announce: " + primary);
}
} else {
_log.warn("No primary announce");
primary = "";
}
List tlist = _util.getOpenTrackers();
if (tlist != null && (meta == null || !meta.isPrivate())) {
if (meta == null || !meta.isPrivate()) {
List<String> tlist = _util.getOpenTrackers();
for (int i = 0; i < tlist.size(); i++) {
String url = (String)tlist.get(i);
String url = tlist.get(i);
if (!isValidAnnounce(url)) {
_log.error("Bad announce URL: [" + url + "]");
continue;
......@@ -301,9 +309,37 @@ public class TrackerClient implements Runnable {
continue;
// opentrackers are primary if we don't have primary
trackers.add(new Tracker(url, primary.equals("")));
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
// backup trackers if DHT needs bootstrapping
if (trackers.isEmpty() && (meta == null || !meta.isPrivate())) {
List<String> tlist = _util.getBackupTrackers();
for (int i = 0; i < tlist.size(); i++) {
String url = tlist.get(i);
if (!isValidAnnounce(url)) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
int slash = url.indexOf('/', 7);
if (slash <= 7) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
String dest = _util.lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url.substring(7, slash) + "]");
continue;
}
backupTrackers.add(new Tracker(url, false));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Backup announce: [" + url + "] for infoHash: " + infoHash);
}
if (backupTrackers.isEmpty())
backupTrackers.add(new Tracker(DEFAULT_BACKUP_TRACKER, false));
}
this.completed = coordinator.getLeft() == 0;
}
......@@ -315,7 +351,7 @@ public class TrackerClient implements Runnable {
private void loop() {
try
{
Random r = I2PAppContext.getGlobalContext().random();
// normally this will only go once, then call queueLoop() and return
while(!stop)
{
if (!verifyConnected()) {
......@@ -325,9 +361,71 @@ public class TrackerClient implements Runnable {
// Local DHT tracker announce
DHT dht = _util.getDHT();
if (dht != null)
if (dht != null && (meta == null || !meta.isPrivate()))
dht.announce(snark.getInfoHash());
int maxSeenPeers = 0;
if (!trackers.isEmpty())
maxSeenPeers = getPeersFromTrackers(trackers);
int p = getPeersFromPEX();
if (p > maxSeenPeers)
maxSeenPeers = p;
p = getPeersFromDHT();
if (p > maxSeenPeers)
maxSeenPeers = p;
// backup if DHT needs bootstrapping
if (trackers.isEmpty() && !backupTrackers.isEmpty() && dht != null && dht.size() < 16) {
p = getPeersFromTrackers(backupTrackers);
if (p > maxSeenPeers)
maxSeenPeers = p;
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
if (stop)
return;
try {
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
int delay;
Random r = _util.getContext().random();
int random = r.nextInt(120*1000);
if (completed && runStarted)
delay = 3*SLEEP*60*1000 + random;
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else if ((!runStarted) && _runCount < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
delay = SLEEP*60*1000 + random;
if (delay > 20*1000) {
// put ourselves on SimpleTimer2
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requeueing in " + DataHelper.formatDuration(delay) + ": " + Thread.currentThread().getName());
queueLoop(delay);
return;
} else if (delay > 0) {
Thread.sleep(delay);
}
} catch(InterruptedException interrupt) {}
} // *** end of while loop
} // try
catch (Throwable t)
{
_log.error("TrackerClient: " + t, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError)t;
}
}
/**
* @return max peers seen
*/
private int getPeersFromTrackers(List<Tracker> trckrs) {
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft(); // -1 in magnet mode
......@@ -341,10 +439,10 @@ public class TrackerClient implements Runnable {
}
else
event = NO_EVENT;
// *** loop once for each tracker
int maxSeenPeers = 0;
for (Tracker tr : trackers) {
for (Tracker tr : trckrs) {
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needOutboundPeers() || !tr.started) &&
(event.equals(COMPLETED_EVENT) || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
......@@ -372,7 +470,7 @@ public class TrackerClient implements Runnable {
snark.setTrackerSeenPeers(tr.seenPeers);
// pass everybody over to our tracker
dht = _util.getDHT();
DHT dht = _util.getDHT();
if (dht != null) {
for (Peer peer : peers) {
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
......@@ -383,6 +481,7 @@ public class TrackerClient implements Runnable {
// we only want to talk to new people if we need things
// from them (duh)
List<Peer> ordered = new ArrayList(peers);
Random r = _util.getContext().random();
Collections.shuffle(ordered, r);
Iterator<Peer> it = ordered.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
......@@ -409,13 +508,13 @@ public class TrackerClient implements Runnable {
snark.setTrackerProblems(tr.trackerProblems);
if (tr.trackerProblems.toLowerCase(Locale.US).startsWith(NOT_REGISTERED)) {
// Give a guy some time to register it if using opentrackers too
if (trackers.size() == 1) {
stop = true;
snark.stopTorrent();
} else { // hopefully each on the opentrackers list is really open
//if (trckrs.size() == 1) {
// stop = true;
// snark.stopTorrent();
//} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS)
tr.stop = true;
}
//
}
if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
tr.seenPeers = 0;
......@@ -432,7 +531,15 @@ public class TrackerClient implements Runnable {
maxSeenPeers = tr.seenPeers;
} // *** end of trackers loop here
return maxSeenPeers;
}
/**
* @return max peers seen
*/
private int getPeersFromPEX() {
// Get peers from PEX
int rv = 0;
if (coordinator.needOutboundPeers() && (meta == null || !meta.isPrivate()) && !stop) {
Set<PeerID> pids = coordinator.getPEXPeers();
if (!pids.isEmpty()) {
......@@ -442,6 +549,7 @@ public class TrackerClient implements Runnable {
for (PeerID pID : pids) {
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
}
Random r = _util.getContext().random();
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
......@@ -451,19 +559,27 @@ public class TrackerClient implements Runnable {
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
rv = pids.size();
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting PEX peers");
}
return rv;
}
/**
* @return max peers seen
*/
private int getPeersFromDHT() {
// Get peers from DHT
// FIXME this needs to be in its own thread
dht = _util.getDHT();
int rv = 0;
DHT dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()) && (!stop) &&
_util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL) {
int numwant;
if (event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers())
if (!coordinator.needOutboundPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
......@@ -471,6 +587,7 @@ public class TrackerClient implements Runnable {
if (!hashes.isEmpty()) {
runStarted = true;
lastDHTAnnounce = _util.getContext().clock().now();
rv = hashes.size();
}
if (_log.shouldLog(Log.INFO))
_log.info("Got " + hashes + " from DHT");
......@@ -487,9 +604,12 @@ public class TrackerClient implements Runnable {
if ((!stop) && !hashes.isEmpty()) {
List<Peer> peers = new ArrayList(hashes.size());
for (Hash h : hashes) {
PeerID pID = new PeerID(h.getData(), _util);
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
try {
PeerID pID = new PeerID(h.getData(), _util);
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
} catch (InvalidBEncodingException ibe) {}
}
Random r = _util.getContext().random();
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
......@@ -504,49 +624,10 @@ public class TrackerClient implements Runnable {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting DHT peers");
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
if (stop)
return;
try {
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
int delay;
int random = r.nextInt(120*1000);
if (completed && runStarted)
delay = 3*SLEEP*60*1000 + random;
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else if ((!runStarted) && _runCount < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
delay = SLEEP*60*1000 + random;
if (delay > 20*1000) {
// put ourselves on SimpleTimer2
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requeueing in " + DataHelper.formatDuration(delay) + ": " + Thread.currentThread().getName());
queueLoop(delay);
return;
} else if (delay > 0) {
Thread.sleep(delay);
}
} catch(InterruptedException interrupt) {}
} // *** end of while loop
} // try
catch (Throwable t)
{
_log.error("TrackerClient: " + t, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError)t;
}
return rv;
}
/**
* Creates a thread for each tracker in parallel if tunnel is still open
* @since 0.9.1
......@@ -630,7 +711,8 @@ public class TrackerClient implements Runnable {
if (! event.equals(NO_EVENT))
buf.append("&event=").append(event);
buf.append("&numwant=");
if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers())
boolean small = left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers();
if (small)
buf.append('0');
else
buf.append(_util.getMaxConnections());
......@@ -641,14 +723,12 @@ public class TrackerClient implements Runnable {
tr.lastRequestTime = System.currentTimeMillis();
// Don't wait for a response to stopped when shutting down
boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
File fetched = _util.get(s, true, fast ? -1 : 0);
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 8*1024);
if (fetched == null) {
throw new IOException("Error fetching " + s);
}
InputStream in = null;
try {
in = new FileInputStream(fetched);
InputStream in = new ByteArrayInputStream(fetched);
TrackerInfo info = new TrackerInfo(in, snark.getID(),
snark.getInfoHash(), snark.getMetaInfo(), _util);
......@@ -661,10 +741,6 @@ public class TrackerClient implements Runnable {
tr.interval = Math.max(MIN_TRACKER_ANNOUNCE_INTERVAL, info.getInterval() * 1000l);
return info;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
fetched.delete();
}
}
/**
......
......@@ -143,6 +143,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/** how long since generated do we delete - BEP 5 says 10 minutes */
private static final long MAX_TOKEN_AGE = 10*60*1000;
private static final long MAX_INBOUND_TOKEN_AGE = MAX_TOKEN_AGE - 2*60*1000;
private static final int MAX_OUTBOUND_TOKENS = 5000;
/** how long since sent do we wait for a reply */
private static final long MAX_MSGID_AGE = 2*60*1000;
/** how long since sent do we wait for a reply */
......@@ -1208,7 +1209,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/**
* Handle and respond to the query.
* We have no node info here, it came on response port, we have to get it from the token
* We have no node info here, it came on response port, we have to get it from the token.
* So we can't verify that it came from the same peer, as BEP 5 specifies.
*/
private void receiveAnnouncePeer(MsgID msgID, InfoHash ih, byte[] tok) throws InvalidBEncodingException {
Token token = new Token(tok);
......@@ -1216,8 +1218,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (nInfo == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unknown token in announce_peer: " + token);
if (_log.shouldLog(Log.INFO))
_log.info("Current known tokens: " + _outgoingTokens.keySet());
//if (_log.shouldLog(Log.INFO))
// _log.info("Current known tokens: " + _outgoingTokens.keySet());
return;
}
if (_log.shouldLog(Log.INFO))
......@@ -1282,8 +1284,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
* @throws NPE, IllegalArgumentException, and others too
*/
private List<NodeInfo> receiveNodes(NodeInfo nInfo, byte[] ids) throws InvalidBEncodingException {
List<NodeInfo> rv = new ArrayList(ids.length / NodeInfo.LENGTH);
for (int off = 0; off < ids.length; off += NodeInfo.LENGTH) {
int max = Math.min(K, ids.length / NodeInfo.LENGTH);
List<NodeInfo> rv = new ArrayList(max);
for (int off = 0; off < ids.length && rv.size() < max; off += NodeInfo.LENGTH) {
NodeInfo nInf = new NodeInfo(ids, off);
if (_blacklist.contains(nInf.getNID())) {
if (_log.shouldLog(Log.INFO))
......@@ -1305,12 +1308,15 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
private List<Hash> receivePeers(NodeInfo nInfo, List<BEValue> peers) throws InvalidBEncodingException {
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd peers from: " + nInfo);
List<Hash> rv = new ArrayList(peers.size());
int max = Math.min(MAX_WANT, peers.size());
List<Hash> rv = new ArrayList(max);
for (BEValue bev : peers) {
byte[] b = bev.getBytes();
//Hash h = new Hash(b);
Hash h = Hash.create(b);
rv.add(h);
if (rv.size() >= max)
break;
}
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd peers from: " + nInfo + ": " + DataHelper.toString(rv));
......@@ -1535,20 +1541,28 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_blacklist.size() + " in blacklist, " +
_outgoingTokens.size() + " sent Tokens, " +
_incomingTokens.size() + " rcvd Tokens");
int cnt = 0;
long expire = now - MAX_TOKEN_AGE;
for (Iterator<Token> iter = _outgoingTokens.keySet().iterator(); iter.hasNext(); ) {
Token tok = iter.next();
if (tok.lastSeen() < now - MAX_TOKEN_AGE)
// just delete at random if we have too many
// TODO reduce the expire time and iterate again?
if (tok.lastSeen() < expire || cnt >= MAX_OUTBOUND_TOKENS)
iter.remove();
else
cnt++;
}
expire = now - MAX_INBOUND_TOKEN_AGE;
for (Iterator<Token> iter = _incomingTokens.values().iterator(); iter.hasNext(); ) {
Token tok = iter.next();
if (tok.lastSeen() < now - MAX_INBOUND_TOKEN_AGE)
if (tok.lastSeen() < expire)
iter.remove();
}
expire = now - BLACKLIST_CLEAN_TIME;
for (Iterator<NID> iter = _blacklist.iterator(); iter.hasNext(); ) {
NID nid = iter.next();
// lastSeen() is actually when-added
if (now > nid.lastSeen() + BLACKLIST_CLEAN_TIME)
if (nid.lastSeen() < expire)
iter.remove();
}
// TODO sent queries?
......
......@@ -53,6 +53,8 @@ class UnsignedUpdateRunner extends UpdateRunner {
} catch (Throwable t) {
_log.error("Error updating", t);
}
if (!this.done)
_mgr.notifyTaskFailed(this, "", null);
}
/** eepget listener callback Overrides */
......
......@@ -3,6 +3,8 @@ package net.i2p.router.web;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.util.RandomSource;
/**
* Copied and modded from I2PTunnel IndexBean (GPL)
* @author zzz
......@@ -11,8 +13,6 @@ public class CSSHelper extends HelperBase {
private static final Map<String, Boolean> _UACache = new ConcurrentHashMap();
public CSSHelper() {}
public static final String PROP_UNIVERSAL_THEMING = "routerconsole.universal.theme";
public static final String PROP_THEME_NAME = "routerconsole.theme";
public static final String DEFAULT_THEME = "light";
......@@ -24,6 +24,16 @@ public class CSSHelper extends HelperBase {
public static final String PROP_DISABLE_REFRESH = "routerconsole.summaryDisableRefresh";
private static final String PROP_XFRAME = "routerconsole.disableXFrame";
private static final String _consoleNonce = Long.toString(RandomSource.getInstance().nextLong());
/**
* formerly stored in System.getProperty("router.consoleNonce")
* @since 0.9.4
*/
public static String getNonce() {
return _consoleNonce;
}
public String getTheme(String userAgent) {
String url = BASE_THEME_PATH;
if (userAgent != null && userAgent.contains("MSIE")) {
......
......@@ -3,6 +3,7 @@ package net.i2p.router.web;
import net.i2p.data.DataHelper;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.util.RandomSource;
/**
* simple helper to control restarts/shutdowns in the left hand nav
......@@ -12,20 +13,18 @@ public class ConfigRestartBean {
/** all these are tagged below so no need to _x them here.
* order is: form value, form class, display text.
*/
static final String[] SET1 = {"shutdownImmediate", "stop", "Shutdown immediately", "cancelShutdown", "cancel", "Cancel shutdown"};
static final String[] SET2 = {"restartImmediate", "reload", "Restart immediately", "cancelShutdown", "cancel", "Cancel restart"};
static final String[] SET3 = {"restart", "reload", "Restart", "shutdown", "stop", "Shutdown"};
static final String[] SET4 = {"shutdown", "stop", "Shutdown"};
private static final String[] SET1 = {"shutdownImmediate", "stop", "Shutdown immediately", "cancelShutdown", "cancel", "Cancel shutdown"};
private static final String[] SET2 = {"restartImmediate", "reload", "Restart immediately", "cancelShutdown", "cancel", "Cancel restart"};
private static final String[] SET3 = {"restart", "reload", "Restart", "shutdown", "stop", "Shutdown"};
private static final String[] SET4 = {"shutdown", "stop", "Shutdown"};
private static final String _systemNonce = Long.toString(RandomSource.getInstance().nextLong());
/** formerly System.getProperty("console.nonce") */
public static String getNonce() {
RouterContext ctx = ContextHelper.getContext(null);
String nonce = System.getProperty("console.nonce");
if (nonce == null) {
nonce = ""+ctx.random().nextLong();
System.setProperty("console.nonce", nonce);
}
return nonce;
return _systemNonce;
}
public static String renderStatus(String urlBase, String action, String nonce) {
RouterContext ctx = ContextHelper.getContext(null);
String systemNonce = getNonce();
......
......@@ -194,8 +194,8 @@ public class FormHandler {
return;
}
String sharedNonce = System.getProperty("router.consoleNonce");
if ( (sharedNonce != null) && (sharedNonce.equals(_nonce) ) ) {
String sharedNonce = CSSHelper.getNonce();
if (sharedNonce.equals(_nonce)) {
return;
}
......
......@@ -212,7 +212,7 @@ public class NewsHelper extends ContentHelper {
ctx));
}
buf.append("</i>");
String consoleNonce = System.getProperty("router.consoleNonce");
String consoleNonce = CSSHelper.getNonce();
if (lastUpdated > 0 && consoleNonce != null) {
if (shouldShowNews(ctx)) {
buf.append(" <a href=\"/?news=0&amp;consoleNonce=").append(consoleNonce).append("\">")
......
......@@ -606,7 +606,7 @@ public class SummaryBarRenderer {
NewsHelper newshelper = _helper.getNewsHelper();
if (newshelper == null || newshelper.shouldShowNews()) return "";
StringBuilder buf = new StringBuilder(512);
String consoleNonce = System.getProperty("router.consoleNonce");
String consoleNonce = CSSHelper.getNonce();
if (consoleNonce != null) {
// Set up title and pre-headings stuff.
buf.append("<h3><a href=\"/configupdate\">")
......
......@@ -809,7 +809,13 @@ public class SummaryHelper extends HelperBase {
private String _requestURI;
public void setRequestURI(String s) { _requestURI = s; }
public String getRequestURI() { return _requestURI; }
/**
* @return non-null; "/home" if (strangely) not set by jsp
*/
public String getRequestURI() {
return _requestURI != null ? _requestURI : "/home";
}
public String getConfigTable() {
String[] allSections = SummaryBarRenderer.ALL_SECTIONS;
......
......@@ -31,15 +31,7 @@ input.default {
<%@include file="formhandler.jsi" %>
<div class="configure"><div class="topshimten"><h3><%=uihelper._("Router Console Theme")%></h3></div>
<form action="" method="POST">
<%
/** lang setting is done in css.jsi, not in ConfigUIHandler */
String consoleNonce = System.getProperty("router.consoleNonce");
if (consoleNonce == null) {
consoleNonce = Long.toString(new java.util.Random().nextLong());
System.setProperty("router.consoleNonce", consoleNonce);
}
%>
<input type="hidden" name="consoleNonce" value="<%=consoleNonce%>" >
<input type="hidden" name="consoleNonce" value="<%=intl.getNonce()%>" >
<input type="hidden" name="nonce" value="<%=pageNonce%>" >
<input type="hidden" name="action" value="blah" >
<%
......
......@@ -10,11 +10,7 @@
<%@include file="summaryajax.jsi" %>
</head><body onload="initAjax()">
<%
String consoleNonce = System.getProperty("router.consoleNonce");
if (consoleNonce == null) {
consoleNonce = Long.toString(new java.util.Random().nextLong());
System.setProperty("router.consoleNonce", consoleNonce);
}
String consoleNonce = intl.getNonce();
%>
<%@include file="summary.jsi" %>
......
......@@ -34,7 +34,7 @@
response.setHeader("X-Frame-Options", "SAMEORIGIN");
String conNonceParam = request.getParameter("consoleNonce");
if (conNonceParam != null && conNonceParam.equals(System.getProperty("router.consoleNonce"))) {
if (intl.getNonce().equals(conNonceParam)) {
intl.setLang(request.getParameter("lang"));
intl.setNews(request.getParameter("news"));
}
......
......@@ -8,11 +8,7 @@
<%@include file="summaryajax.jsi" %>
</head><body onload="initAjax()">
<%
String consoleNonce = System.getProperty("router.consoleNonce");
if (consoleNonce == null) {
consoleNonce = Long.toString(new java.util.Random().nextLong());
System.setProperty("router.consoleNonce", consoleNonce);
}
String consoleNonce = intl.getNonce();
%>
<jsp:useBean class="net.i2p.router.web.NewsHelper" id="newshelper" scope="request" />
<jsp:setProperty name="newshelper" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
......
2012-11-05 zzz
* Console:
- Fix NPE after restart (ticket #763)
- Move more nonces out of system properties
* i2psnark:
- More DHT limits
- Announce to backup trackers if DHT is empty
- Use PEX and DHT info in torrent peer count
- Don't use temp files for announces
* PeerManager: Don't reorganize as often if it takes too long (ticket #765)
* RequestLeaseSetJob: Only disconnect client after multiple dropped
lease set requests; reduce timeout, other cleanups
* Unsigned Update: Fix notification on failure
2012-11-02 kytv
* German, Portuguese, and Swedish translation updates from Transifex
* Refreshed English po files to push to TX.
* German, Portuguese, and Swedish translation updates from Transifex
* Refreshed English po files to push to TX.
2012-11-02 zzz
* configstats: Fix group sorting, translate groups
......
......@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 4;
public final static long BUILD = 5;
/** for example "-test" */
public final static String EXTRA = "";
......
......@@ -71,6 +71,7 @@ class ClientConnectionRunner {
private final Map<MessageId, Payload> _messages;
/** lease set request state, or null if there is no request pending on at the moment */
private LeaseRequestState _leaseRequest;
private int _consecutiveLeaseRequestFails;
/** currently allocated leaseSet, or null if none is allocated */
private LeaseSet _currentLeaseSet;
/** set of messageIds created but not yet ACCEPTED */
......@@ -100,6 +101,7 @@ class ClientConnectionRunner {
// e.g. on local access
private static final int MAX_MESSAGE_ID = 0x4000000;
private static final int MAX_LEASE_FAILS = 5;
private static final int BUF_SIZE = 32*1024;
/** @since 0.9.2 */
......@@ -191,12 +193,17 @@ class ClientConnectionRunner {
/** data for the current leaseRequest, or null if there is no active leaseSet request */
LeaseRequestState getLeaseRequest() { return _leaseRequest; }
void setLeaseRequest(LeaseRequestState req) {
/** @param req non-null */
public void failLeaseRequest(LeaseRequestState req) {
boolean disconnect = false;
synchronized (this) {
if ( (_leaseRequest != null) && (req != _leaseRequest) )
_log.error("Changing leaseRequest from " + _leaseRequest + " to " + req);
_leaseRequest = req;
if (_leaseRequest == req) {
_leaseRequest = null;
disconnect = ++_consecutiveLeaseRequestFails > MAX_LEASE_FAILS;
}
}
if (disconnect)
disconnectClient("Too many leaseset request fails");
}
/** already closed? */
......@@ -287,6 +294,7 @@ class ClientConnectionRunner {
if (_log.shouldLog(Log.DEBUG))
_log.debug("LeaseSet created fully: " + state + " / " + ls);
_leaseRequest = null;
_consecutiveLeaseRequestFails = 0;
}
}
if ( (state != null) && (state.getOnGranted() != null) )
......@@ -351,9 +359,8 @@ class ClientConnectionRunner {
_acceptedPending.add(id);
if (_log.shouldLog(Log.DEBUG))
_log.debug("** Receiving message [" + id.getMessageId() + "] with payload of size ["
+ payload.getSize() + "]" + " for session [" + _sessionId.getSessionId()
+ "]");
_log.debug("** Receiving message " + id.getMessageId() + " with payload of size "
+ payload.getSize() + " for session " + _sessionId.getSessionId());
//long beforeDistribute = _context.clock().now();
// the following blocks as described above
SessionConfig cfg = _config;
......@@ -380,7 +387,7 @@ class ClientConnectionRunner {
if (sid == null) return;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Acking message send [accepted]" + id + " / " + nonce + " for sessionId "
+ sid, new Exception("sendAccepted"));
+ sid);
MessageStatusMessage status = new MessageStatusMessage();
status.setMessageId(id.getMessageId());
status.setSessionId(sid.getSessionId());
......@@ -486,10 +493,11 @@ class ClientConnectionRunner {
return; // already requesting
} else {
_leaseRequest = state = new LeaseRequestState(onCreateJob, onFailedJob, _context.clock().now() + expirationTime, set);
_log.debug("Not already requesting, continue to request " + set);
if (_log.shouldLog(Log.DEBUG))
_log.debug("New request: " + state);
}
}
_context.jobQueue().addJob(new RequestLeaseSetJob(_context, this, set, _context.clock().now() + expirationTime, onCreateJob, onFailedJob, state));
_context.jobQueue().addJob(new RequestLeaseSetJob(_context, this, state));
}
private class Rerequest implements SimpleTimer.TimedEvent {
......@@ -646,8 +654,8 @@ class ClientConnectionRunner {
if (!alreadyAccepted(_messageId)) {
_log.warn("Almost send an update for message " + _messageId + " to "
+ MessageStatusMessage.getStatusString(msg.getStatus())
+ " for session [" + _sessionId.getSessionId()
+ "] before they knew the messageId! delaying .5s");
+ " for session " + _sessionId.getSessionId()
+ " before they knew the messageId! delaying .5s");
_lastTried = _context.clock().now();
requeue(REQUEUE_DELAY);
return;
......@@ -680,15 +688,14 @@ class ClientConnectionRunner {
if (_log.shouldLog(Log.DEBUG))
_log.info("Updating message status for message " + _messageId + " to "
+ MessageStatusMessage.getStatusString(msg.getStatus())
+ " for session [" + _sessionId.getSessionId()
+ "] (with nonce=2), retrying after ["
+ (_context.clock().now() - _lastTried)
+ "]");
+ " for session " + _sessionId.getSessionId()
+ " (with nonce=2), retrying after "
+ (_context.clock().now() - _lastTried));
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Updating message status for message " + _messageId + " to "
+ MessageStatusMessage.getStatusString(msg.getStatus())
+ " for session [" + _sessionId.getSessionId() + "] (with nonce=2)");
+ " for session " + _sessionId.getSessionId() + " (with nonce=2)");
}
try {
......
......@@ -62,6 +62,8 @@ class ClientManager {
private static final int INTERNAL_QUEUE_SIZE = 256;
private static final long REQUEST_LEASESET_TIMEOUT = 60*1000;
public ClientManager(RouterContext context, int port) {
_ctx = context;
_log = context.logManager().getLog(ClientManager.class);
......@@ -275,6 +277,8 @@ class ClientManager {
* within the timeout specified, queue up the onFailedJob. This call does not
* block.
*
* UNUSED, the call below without jobs is always used.
*
* @param dest Destination from which the LeaseSet's authorization should be requested
* @param set LeaseSet with requested leases - this object must be updated to contain the
* signed version (as well as any changed/added/removed Leases)
......@@ -290,12 +294,10 @@ class ClientManager {
+ dest.calculateHash().toBase64() + ". disconnected?");
_ctx.jobQueue().addJob(onFailedJob);
} else {
runner.requestLeaseSet(set, _ctx.clock().now() + timeout, onCreateJob, onFailedJob);
runner.requestLeaseSet(set, timeout, onCreateJob, onFailedJob);
}
}
private static final int REQUEST_LEASESET_TIMEOUT = 120*1000;
public void requestLeaseSet(Hash dest, LeaseSet ls) {
ClientConnectionRunner runner = getRunner(dest);
if (runner != null) {
......
......@@ -110,6 +110,8 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade implements Inte
* within the timeout specified, queue up the onFailedJob. This call does not
* block.
*
* UNUSED, the call below without jobs is always used.
*
* @param dest Destination from which the LeaseSet's authorization should be requested
* @param set LeaseSet with requested leases - this object must be updated to contain the
* signed version (as well as any changed/added/removed Leases)
......
......@@ -28,6 +28,9 @@ class LeaseRequestState {
private final long _expiration;
private boolean _successful;
/**
* @param expiration absolute time
*/
public LeaseRequestState(Job onGranted, Job onFailed, long expiration, LeaseSet requested) {
_onGranted = onGranted;
_onFailed = onFailed;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment