merge of '0035c4f64c2b0f23c9e007363b634f360e2f10cb'

and '0c2d5fea1f036773ef51ce22d9d8c4e9203ee5f3'
This commit is contained in:
zzz
2011-12-17 18:52:23 +00:00
15 changed files with 181 additions and 63 deletions

View File

@@ -23,11 +23,15 @@ package org.klomp.snark;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.crypto.SHA1;
import net.i2p.util.SecureFile;
@@ -67,6 +71,8 @@ public class Storage
public static final int MAX_PIECES = 10*1024;
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap();
/**
* Creates a new storage based on the supplied MetaInfo. This will
* try to create and/or check all needed files in the MetaInfo.
@@ -568,20 +574,48 @@ public class Storage
/**
* Removes 'suspicious' characters from the given file name.
* http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx
* Then replace chars not supported in the charset.
*
* This is called frequently and it can be pretty slow so cache the result.
*
* TODO: If multiple files in the same torrent map to the same filter name,
* the whole torrent will blow up. Check at torrent creation?
*/
public static String filterName(String name)
{
if (name.equals(".") || name.equals(" "))
return "_";
String rv = name;
if (rv.startsWith("."))
rv = '_' + rv.substring(1);
if (rv.endsWith(".") || rv.endsWith(" "))
rv = rv.substring(0, rv.length() - 1) + '_';
for (int i = 0; i < ILLEGAL.length; i++) {
if (rv.indexOf(ILLEGAL[i]) >= 0)
rv = rv.replace(ILLEGAL[i], '_');
}
String rv = _filterNameCache.get(name);
if (rv != null)
return rv;
if (name.equals(".") || name.equals(" ")) {
rv = "_";
} else {
rv = name;
if (rv.startsWith("."))
rv = '_' + rv.substring(1);
if (rv.endsWith(".") || rv.endsWith(" "))
rv = rv.substring(0, rv.length() - 1) + '_';
for (int i = 0; i < ILLEGAL.length; i++) {
if (rv.indexOf(ILLEGAL[i]) >= 0)
rv = rv.replace(ILLEGAL[i], '_');
}
// Replace characters not supported in the charset
if (!Charset.defaultCharset().name().equals("UTF-8")) {
try {
CharsetEncoder enc = Charset.defaultCharset().newEncoder();
if (!enc.canEncode(rv)) {
String repl = rv;
for (int i = 0; i < rv.length(); i++) {
char c = rv.charAt(i);
if (!enc.canEncode(c))
repl = repl.replace(c, '_');
}
rv = repl;
}
} catch (Exception ex) {
ex.printStackTrace();
}
} }
_filterNameCache.put(name, rv);
return rv;
}

View File

@@ -1759,6 +1759,7 @@ public class I2PSnarkServlet extends Default {
// We don't have the hash of the torrent file
//buf.append("<br>").append(_("Maggot link")).append(": <a href=\"").append(MAGGOT).append(hex).append(':').append(hex).append("\">")
// .append(MAGGOT).append(hex).append(':').append(hex).append("</a>");
buf.append("<br>").append(_("Torrent file")).append(": ").append(snark.getName());
buf.append("</div></th></tr>");
}
if (ls == null) {

View File

@@ -888,7 +888,7 @@
<arg value="history.txt" />
</exec>
<exec executable="echo" osfamily="unix" failifexecutionfails="true" output="pkg-temp/history.txt" append="true">
<arg value="EARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE" />
<arg value="&#10;&#10;----------------&#10;&#10;EARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE" />
</exec>
<copy file="installer/resources/deletelist.txt" todir="pkg-temp/" />
<!-- May be pointless now, people with split directories will never see this,

View File

@@ -235,7 +235,7 @@ public class SimpleTimer2 {
if (_log.shouldLog(Log.WARN) && delay > 100)
_log.warn(_pool + " wtf, early execution " + delay + ": " + this);
else if (_log.shouldLog(Log.WARN) && delay < -1000)
_log.warn(" wtf, late execution " + delay + ": " + this + _pool.debug());
_log.warn(" wtf, late execution " + (0 - delay) + ": " + this + _pool.debug());
try {
timeReached();
} catch (Throwable t) {

View File

@@ -1,3 +1,11 @@
2011-12-17 zzz
* i2psnark:
- Replace file name characters not supported in default charset
- Add torrent file name to local details page
* GeoIP: Reduce thread priority during lookup
* ProfileManager: Make some methods non-blocking to reduce
lock contention in transports
2011-12-15 kytv
* Swedish translation updates from Transifex

View File

@@ -146,14 +146,15 @@ public class InNetMessagePool implements Service {
//if (messageBody instanceof TunnelCreateMessage)
// level = Log.INFO;
if (_log.shouldLog(level))
_log.log(level, "Duplicate message received [" + messageBody.getUniqueId()
+ " expiring on " + exp + "]: " + messageBody.getClass().getName() + ": " + invalidReason
_log.log(level, "Dropping message [" + messageBody.getUniqueId()
+ " expiring on " + exp + "]: " + messageBody.getClass().getSimpleName() + ": " + invalidReason
+ ": " + messageBody);
_context.statManager().addRateData("inNetPool.dropped", 1, 0);
// FIXME not necessarily a duplicate, could be expired too long ago / too far in future
_context.statManager().addRateData("inNetPool.duplicate", 1, 0);
_context.messageHistory().droppedOtherMessage(messageBody, (fromRouter != null ? fromRouter.calculateHash() : fromRouterHash));
_context.messageHistory().messageProcessingError(messageBody.getUniqueId(),
messageBody.getClass().getName(),
messageBody.getClass().getSimpleName(),
"Duplicate/expired");
return -1;
} else {

View File

@@ -18,10 +18,10 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 21;
public final static long BUILD = 22;
/** for example "-test" */
public final static String EXTRA = "";
public final static String EXTRA = "-rc";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
public static void main(String args[]) {
System.out.println("I2P Router version: " + FULL_VERSION);

View File

@@ -112,7 +112,7 @@ public class GarlicMessageReceiver {
_log.warn("Clove is NOT valid: id=" + clove.getCloveId()
+ " expiration " + howLongAgo + " ago: " + invalidReason + ": " + clove);
_context.messageHistory().messageProcessingError(clove.getCloveId(),
clove.getData().getClass().getName(),
clove.getData().getClass().getSimpleName(),
"Clove is not valid (expiration " + howLongAgo + " ago)");
}
return (invalidReason == null);

View File

@@ -21,6 +21,10 @@ import net.i2p.router.ProfileManager;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
/**
* Methods to update profiles.
* Unless otherwise noted, methods are blocking on the reorganize lock.
*/
public class ProfileManagerImpl implements ProfileManager {
private final Log _log;
private final RouterContext _context;
@@ -33,31 +37,31 @@ public class ProfileManagerImpl implements ProfileManager {
/**
* Note that it took msToSend to send a message of size bytesSent to the peer over the transport.
* This should only be called if the transport considered the send successful.
*
* Non-blocking. Will not update the profile if we can't get the lock.
*/
public void messageSent(Hash peer, String transport, long msToSend, long bytesSent) {
PeerProfile data = getProfile(peer);
PeerProfile data = getProfileNonblocking(peer);
if (data == null) return;
data.setLastSendSuccessful(_context.clock().now());
//data.getSendSuccessSize().addData(bytesSent, msToSend);
}
/**
* Note that the router failed to send a message to the peer over the transport specified
*
* Note that the router failed to send a message to the peer over the transport specified.
* Non-blocking. Will not update the profile if we can't get the lock.
*/
public void messageFailed(Hash peer, String transport) {
PeerProfile data = getProfile(peer);
PeerProfile data = getProfileNonblocking(peer);
if (data == null) return;
data.setLastSendFailed(_context.clock().now());
}
/**
* Note that the router failed to send a message to the peer over any transport
*
* Note that the router failed to send a message to the peer over any transport.
* Non-blocking. Will not update the profile if we can't get the lock.
*/
public void messageFailed(Hash peer) {
PeerProfile data = getProfile(peer);
PeerProfile data = getProfileNonblocking(peer);
if (data == null) return;
data.setLastSendFailed(_context.clock().now());
}
@@ -70,7 +74,7 @@ public class ProfileManagerImpl implements ProfileManager {
if (_log.shouldLog(Log.INFO))
_log.info("Comm error occurred for peer " + peer.toBase64(), new Exception("Comm error"));
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastSendFailed(_context.clock().now());
}
@@ -80,7 +84,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void tunnelJoined(Hash peer, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.getTunnelCreateResponseTime().addData(responseTimeMs, responseTimeMs);
data.setLastHeardFrom(_context.clock().now());
data.getTunnelHistory().incrementAgreedTo();
@@ -95,7 +99,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void tunnelRejected(Hash peer, long responseTimeMs, int severity) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
data.getTunnelHistory().incrementRejected(severity);
}
@@ -108,7 +112,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void tunnelTimedOut(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.getTunnelHistory().incrementRejected(TunnelHistory.TUNNEL_REJECT_BANDWIDTH);
}
@@ -119,7 +123,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void tunnelTestSucceeded(Hash peer, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.updateTunnelTestTimeAverage(responseTimeMs);
data.getTunnelTestResponseTime().addData(responseTimeMs, responseTimeMs);
}
@@ -128,14 +132,15 @@ public class ProfileManagerImpl implements ProfileManager {
if (_context.routerHash().equals(peer))
return;
PeerProfile data = getProfile(peer);
if (data != null)
//if (data != null)
data.dataPushed(size); // ignore rtt, as we are averaging over a minute
}
public void tunnelDataPushed1m(Hash peer, int size) {
if (_context.routerHash().equals(peer))
return;
PeerProfile data = getProfile(peer);
if (data != null)
//if (data != null)
data.dataPushed1m(size);
}
@@ -144,7 +149,7 @@ public class ProfileManagerImpl implements ProfileManager {
if (_context.routerHash().equals(peer))
return;
PeerProfile data = getProfile(peer);
if (data != null)
//if (data != null)
data.tunnelDataTransferred(size);
}
@@ -162,7 +167,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void tunnelFailed(Hash peer, int pct) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
data.getTunnelHistory().incrementFailed(pct);
}
@@ -174,7 +179,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbLookupSuccessful(Hash peer, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
if (!data.getIsExpandedDB())
data.expandDBProfile();
@@ -191,7 +196,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbLookupFailed(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
if (!data.getIsExpandedDB())
data.expandDBProfile();
DBHistory hist = data.getDBHistory();
@@ -208,7 +213,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbLookupReply(Hash peer, int newPeers, int oldPeers, int invalid, int duplicate, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
if (!data.getIsExpandedDB())
return;
@@ -224,7 +229,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbLookupReceived(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
if (!data.getIsExpandedDB())
return;
@@ -238,7 +243,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbStoreReceived(Hash peer, boolean wasNewKey) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
if (!data.getIsExpandedDB())
return;
@@ -257,7 +262,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbStoreSent(Hash peer, long responseTimeMs) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
long now = _context.clock().now();
data.setLastHeardFrom(now);
data.setLastSendSuccessful(now);
@@ -275,7 +280,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbStoreSuccessful(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
long now = _context.clock().now();
data.setLastHeardFrom(now);
data.setLastSendSuccessful(now);
@@ -293,7 +298,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void dbStoreFailed(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
if (!data.getIsExpandedDB())
data.expandDBProfile();
DBHistory hist = data.getDBHistory();
@@ -308,7 +313,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void heardAbout(Hash peer) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
data.setLastHeardAbout(_context.clock().now());
}
@@ -318,7 +323,7 @@ public class ProfileManagerImpl implements ProfileManager {
*/
public void heardAbout(Hash peer, long when) {
PeerProfile data = getProfile(peer);
if (data == null) return;
//if (data == null) return;
if (when > data.getLastHeardAbout())
data.setLastHeardAbout(when);
}
@@ -327,16 +332,21 @@ public class ProfileManagerImpl implements ProfileManager {
* Note that the router received a message from the given peer on the specified
* transport. Messages received without any "from" information aren't recorded
* through this metric. If msToReceive is negative, there was no timing information
* available
*
* available.
* Non-blocking. Will not update the profile if we can't get the lock.
*/
public void messageReceived(Hash peer, String style, long msToReceive, int bytesRead) {
PeerProfile data = getProfile(peer);
PeerProfile data = getProfileNonblocking(peer);
if (data == null) return;
data.setLastHeardFrom(_context.clock().now());
//data.getReceiveSize().addData(bytesRead, msToReceive);
}
/**
* Blocking.
* Creates a new profile if it didn't exist.
* @return non-null
*/
private PeerProfile getProfile(Hash peer) {
PeerProfile prof = _context.profileOrganizer().getProfile(peer);
if (prof == null) {
@@ -347,14 +357,28 @@ public class ProfileManagerImpl implements ProfileManager {
return prof;
}
/**
* Non-blocking.
* @return null if the profile doesn't exist, or the fetch would have blocked
* @since 0.8.12
*/
private PeerProfile getProfileNonblocking(Hash peer) {
return _context.profileOrganizer().getProfileNonblocking(peer);
}
/** provide a simple summary of a number of peers, suitable for publication in the netDb */
/**
* provide a simple summary of a number of peers, suitable for publication in the netDb
* @deprecated unused
*/
public Properties summarizePeers(int numPeers) {
/****
Set peers = new HashSet(numPeers);
// lets get the fastest ones we've got (this fails over to include just plain reliable,
// or even notFailing peers if there aren't enough fast ones)
_context.profileOrganizer().selectFastPeers(numPeers, null, peers);
****/
Properties props = new Properties();
/****
for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
Hash peer = (Hash)iter.next();
PeerProfile prof = getProfile(peer);
@@ -384,11 +408,14 @@ public class ProfileManagerImpl implements ProfileManager {
props.setProperty("profile." + peer.toBase64().replace('=', '_'), buf.toString());
}
****/
return props;
}
/****
private final static DecimalFormat _fmt = new DecimalFormat("##0.00", new DecimalFormatSymbols(Locale.UK));
private final static String num(double val) {
synchronized (_fmt) { return _fmt.format(val); }
}
****/
}

View File

@@ -52,7 +52,7 @@ public class ProfileOrganizer {
private final Map<Hash, PeerProfile> _notFailingPeers;
/** H(routerIdnetity), containing elements in _notFailingPeers */
private final List<Hash> _notFailingPeersList;
/** H(routerIdentity) to PeerProfile for all peers that ARE failing horribly (but that we haven't dropped reference to yet) */
/** TO BE REMOVED H(routerIdentity) to PeerProfile for all peers that ARE failing horribly (but that we haven't dropped reference to yet) */
private final Map<Hash, PeerProfile> _failingPeers;
/** who are we? */
private Hash _us;
@@ -120,6 +120,15 @@ public class ProfileOrganizer {
_reorganizeLock.readLock().lock();
}
/**
* Get the lock if we can. Non-blocking.
* @return true if the lock was acquired
* @since 0.8.12
*/
private boolean tryReadLock() {
return _reorganizeLock.readLock().tryLock();
}
private void releaseReadLock() {
_reorganizeLock.readLock().unlock();
}
@@ -147,8 +156,8 @@ public class ProfileOrganizer {
public double getIntegrationThreshold() { return _thresholdIntegrationValue; }
/**
* Retrieve the profile for the given peer, if one exists (else null)
*
* Retrieve the profile for the given peer, if one exists (else null).
* Blocking if a reorganize is happening.
*/
public PeerProfile getProfile(Hash peer) {
getReadLock();
@@ -157,6 +166,20 @@ public class ProfileOrganizer {
} finally { releaseReadLock(); }
}
/**
* Retrieve the profile for the given peer, if one exists (else null).
* Non-blocking. Returns null if a reorganize is happening.
* @since 0.8.12
*/
public PeerProfile getProfileNonblocking(Hash peer) {
if (tryReadLock()) {
try {
return locked_getProfile(peer);
} finally { releaseReadLock(); }
}
return null;
}
/**
* Add the new profile, returning the old value (or null if no profile existed)
*
@@ -243,7 +266,15 @@ public class ProfileOrganizer {
public boolean isFast(Hash peer) { return isX(_fastPeers, peer); }
public boolean isHighCapacity(Hash peer) { return isX(_highCapacityPeers, peer); }
public boolean isWellIntegrated(Hash peer) { return isX(_wellIntegratedPeers, peer); }
public boolean isFailing(Hash peer) { return isX(_failingPeers, peer); }
/**
* Deprecated for now, always false
*/
public boolean isFailing(Hash peer) {
// Always false so skip the lock
//return isX(_failingPeers, peer);
return false;
}
/** @since 0.8.8 */
void clearProfiles() {

View File

@@ -98,9 +98,17 @@ class GeoIP {
_pendingSearch.clear();
return;
}
LookupJob j = new LookupJob();
j.run();
updateOurCountry();
int pri = Thread.currentThread().getPriority();
if (pri > Thread.MIN_PRIORITY)
Thread.currentThread().setPriority(pri - 1);
try {
LookupJob j = new LookupJob();
j.run();
updateOurCountry();
} finally {
if (pri > Thread.MIN_PRIORITY)
Thread.currentThread().setPriority(pri);
}
}
private class LookupJob implements Runnable {

View File

@@ -126,7 +126,7 @@ class IntroductionManager {
_log.info("Picked peer has no SSU address: " + ri);
continue;
}
if (_context.profileOrganizer().isFailing(cur.getRemotePeer()) ||
if ( /* _context.profileOrganizer().isFailing(cur.getRemotePeer()) || */
_context.shitlist().isShitlisted(cur.getRemotePeer()) ||
_transport.wasUnreachable(cur.getRemotePeer())) {
if (_log.shouldLog(Log.INFO))

View File

@@ -12,7 +12,7 @@ import net.i2p.util.Log;
* want. The hop processor works the same on all peers -
* inbound and outbound participants, outbound endpoints,
* and inbound gateways (with a small modification per
* InbuondGatewayProcessor).
* InboundGatewayProcessor).
*
*/
class HopProcessor {
@@ -77,7 +77,7 @@ class HopProcessor {
boolean okIV = _validator.receiveIV(orig, offset, orig, offset + IV_LENGTH);
if (!okIV) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid IV received on tunnel " + _config.getReceiveTunnel());
_log.warn("Invalid IV, dropping at hop " + _config);
return false;
}
@@ -111,4 +111,12 @@ class HopProcessor {
private final void updateIV(byte orig[], int offset) {
_context.aes().encryptBlock(orig, offset, _config.getIVKey(), orig, offset);
}
/**
* @since 0.8.12
*/
@Override
public String toString() {
return getClass().getSimpleName() + " for " + _config;
}
}

View File

@@ -63,7 +63,7 @@ class InboundEndpointProcessor {
boolean ok = _validator.receiveIV(iv, 0, orig, offset + HopProcessor.IV_LENGTH);
if (!ok) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid IV received");
_log.warn("Invalid IV, dropping at IBEP " + _config);
_cache.release(ba);
return false;
}

View File

@@ -80,8 +80,8 @@ public class TunnelPool {
synchronized (_inProgress) {
_inProgress.clear();
}
if (_log.shouldLog(Log.WARN))
_log.warn(toString() + ": Startup() called, was already alive? " + _alive, new Exception());
if (_log.shouldLog(Log.INFO))
_log.info(toString() + ": Startup() called, was already alive? " + _alive, new Exception());
_alive = true;
_started = System.currentTimeMillis();
_lastRateUpdate = _started;