forked from I2P_Developers/i2p.i2p
2005-03-11 jrandom
* Rather than the fixed resend timeout floor (10s), use 10s+RTT as the
minimum (increased on resends as before, of course).
* Always prod the clock update listeners, even if just to tell them that
the time hasn't changed much.
* Added support for explicit peer selection for individual tunnel pools,
which will be useful in debugging but not recommended for use by normal
end users.
* More aggressively search for the next hop's routerInfo on tunnel join.
* Give messages received via inbound tunnels that are bound to remote
locations sufficient time (taking into account clock skew).
* Give alternate direct send messages sufficient time (10s min, not 5s)
* Always give the end to end data message the explicit timeout (though the
old default was sufficient before)
* No need to give end to end messages an insane expiration (+2m), as we
are already handling skew on the receiving side.
* Don't complain too loudly about expired TunnelCreateMessages (at least,
not until after all those 0.5 and 0.5.0.1 users upgrade ;)
* Properly keep the sendBps stat
* When running the router with router.keepHistory=true, log more data to
messageHistory.txt
* Logging updates
* Minor formatting updates
84 lines
3.7 KiB
Java
84 lines
3.7 KiB
Java
package net.i2p.router;
|
|
|
|
import net.i2p.util.DecayingBloomFilter;
|
|
import net.i2p.util.Log;
|
|
|
|
/**
|
|
* Singleton to manage the logic (and historical data) to determine whether a message
|
|
* is valid or not (meaning it isn't expired and hasn't already been received). We'll
|
|
* need a revamp once we start dealing with long message expirations (since it might
|
|
* involve keeping a significant number of entries in memory), but that probably won't
|
|
* be necessary until I2P 3.0.
|
|
*
|
|
*/
|
|
public class MessageValidator {
|
|
private Log _log;
|
|
private RouterContext _context;
|
|
private DecayingBloomFilter _filter;
|
|
|
|
|
|
public MessageValidator(RouterContext context) {
|
|
_log = context.logManager().getLog(MessageValidator.class);
|
|
_filter = null;
|
|
_context = context;
|
|
context.statManager().createRateStat("router.duplicateMessageId", "Note that a duplicate messageId was received", "Router",
|
|
new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
|
|
context.statManager().createRateStat("router.invalidMessageTime", "Note that a message outside the valid range was received", "Router",
|
|
new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
|
|
}
|
|
|
|
|
|
/**
|
|
* Determine if this message should be accepted as valid (not expired, not a duplicate)
|
|
*
|
|
* @return reason why the message is invalid (or null if the message is valid)
|
|
*/
|
|
public String validateMessage(long messageId, long expiration) {
|
|
long now = _context.clock().now();
|
|
if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago");
|
|
_context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0);
|
|
return "expired " + (now-expiration) + "ms ago";
|
|
} else if (now + 4*Router.CLOCK_FUDGE_FACTOR < expiration) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Rejecting message " + messageId + " because it will expire too far in the future (" + (expiration-now) + "ms)");
|
|
_context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0);
|
|
return "expire too far in the future (" + (expiration-now) + "ms)";
|
|
}
|
|
|
|
boolean isDuplicate = noteReception(messageId, expiration);
|
|
if (isDuplicate) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Rejecting message " + messageId + " because it is a duplicate", new Exception("Duplicate origin"));
|
|
_context.statManager().addRateData("router.duplicateMessageId", 1, 0);
|
|
return "duplicate";
|
|
} else {
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
_log.debug("Accepting message " + messageId + " because it is NOT a duplicate", new Exception("Original origin"));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Note that we've received the message (which has the expiration given).
|
|
* This functionality will need to be reworked for I2P 3.0 when we take into
|
|
* consideration messages with significant user specified delays (since we dont
|
|
* want to keep an infinite number of messages in RAM, etc)
|
|
*
|
|
* @return true if we HAVE already seen this message, false if not
|
|
*/
|
|
private boolean noteReception(long messageId, long messageExpiration) {
|
|
boolean dup = _filter.add(messageId);
|
|
return dup;
|
|
}
|
|
|
|
public void startup() {
|
|
_filter = new DecayingBloomFilter(_context, (int)Router.CLOCK_FUDGE_FACTOR * 2, 8);
|
|
}
|
|
|
|
void shutdown() {
|
|
_filter.stopDecaying();
|
|
}
|
|
}
|