2006-02-24 jrandom

* Rounding calculation cleanup in the stats, and avoid an uncontested
      mutex (thanks ripple!)
    * SSU handshake cleanup to help force incompatible peers to stop nagging
      us by both not giving them an updated reference to us and by dropping
      future handshake packets from them.
This commit is contained in:
jrandom
2006-02-24 09:35:52 +00:00
committed by zzz
parent 3d8d21e543
commit 7b2a435aad
9 changed files with 137 additions and 28 deletions

View File

@ -187,10 +187,10 @@ public class Rate {
// ok ok, lets coalesce
// how much were we off by? (so that we can sample down the measured values)
double periodFactor = measuredPeriod / _period;
_lastTotalValue = (_currentTotalValue == 0 ? 0.0D : _currentTotalValue / periodFactor);
_lastEventCount = (_currentEventCount == 0 ? 0L : (long) (_currentEventCount / periodFactor));
_lastTotalEventTime = (_currentTotalEventTime == 0 ? 0L : (long) (_currentTotalEventTime / periodFactor));
double periodFactor = measuredPeriod / (double)_period;
_lastTotalValue = _currentTotalValue / periodFactor;
_lastEventCount = (long) (_currentEventCount / periodFactor);
_lastTotalEventTime = (long) (_currentTotalEventTime / periodFactor);
_lastCoalesceDate = now;
if (_lastTotalValue > _extremeTotalValue) {
@ -237,10 +237,12 @@ public class Rate {
*/
public double getLastEventSaturation() {
if ((_lastEventCount > 0) && (_lastTotalEventTime > 0)) {
double eventTime = (double) _lastTotalEventTime / (double) _lastEventCount;
/*double eventTime = (double) _lastTotalEventTime / (double) _lastEventCount;
double maxEvents = _period / eventTime;
double saturation = _lastEventCount / maxEvents;
return saturation;
*/
return ((double)_lastTotalEventTime) / (double)_period;
}
return 0.0D;

View File

@ -146,15 +146,15 @@ public class DecayingBloomFilter {
for (int i = 0; i < _extenders.length; i++)
DataHelper.xor(entry, offset, _extenders[i], 0, _extended, _entryBytes * (i+1), _entryBytes);
boolean seen = _current.member(_extended);
seen = seen || _previous.member(_extended);
boolean seen = _current.locked_member(_extended);
seen = seen || _previous.locked_member(_extended);
if (seen) {
_currentDuplicates++;
return true;
} else {
if (addIfNew) {
_current.insert(_extended);
_previous.insert(_extended);
_current.locked_insert(_extended);
_previous.locked_insert(_extended);
}
return false;
}

View File

@ -1,4 +1,11 @@
$Id: history.txt,v 1.417 2006/02/23 03:08:37 jrandom Exp $
$Id: history.txt,v 1.418 2006/02/23 09:38:41 jrandom Exp $
2006-02-24 jrandom
* Rounding calculation cleanup in the stats, and avoid an uncontested
mutex (thanks ripple!)
* SSU handshake cleanup to help force incompatible peers to stop nagging
us by both not giving them an updated reference to us and by dropping
future handshake packets from them.
2006-02-23 jrandom
* Increase the SSU retransmit ceiling (for slow links)

View File

@ -1014,8 +1014,8 @@ public class Router {
class CoalesceStatsJob extends JobImpl {
public CoalesceStatsJob(RouterContext ctx) {
super(ctx);
ctx.statManager().createRateStat("bw.receiveBps", "How fast we receive data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("bw.sendBps", "How fast we send data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("bw.receiveBps", "How fast we receive data (in KBps)", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("bw.sendBps", "How fast we send data (in KBps)", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("router.activePeers", "How many peers we are actively talking with", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("router.highCapacityPeers", "How many high capacity peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("router.fastPeers", "How many fast peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
@ -1029,8 +1029,8 @@ class CoalesceStatsJob extends JobImpl {
Rate rate = receiveRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
getContext().statManager().addRateData("bw.receiveBps", (long)bps, 60*1000);
double KBps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
getContext().statManager().addRateData("bw.receiveBps", (long)KBps, 60*1000);
}
}
@ -1039,8 +1039,8 @@ class CoalesceStatsJob extends JobImpl {
Rate rate = sendRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
getContext().statManager().addRateData("bw.sendBps", (long)bps, 60*1000);
double KBps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
getContext().statManager().addRateData("bw.sendBps", (long)KBps, 60*1000);
}
}

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
public final static String ID = "$Revision: 1.358 $ $Date: 2006/02/22 20:48:47 $";
public final static String ID = "$Revision: 1.359 $ $Date: 2006/02/23 09:38:40 $";
public final static String VERSION = "0.6.1.11";
public final static long BUILD = 3;
public final static long BUILD = 4;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -16,6 +16,8 @@ import net.i2p.data.RouterIdentity;
import net.i2p.data.SessionKey;
import net.i2p.data.Signature;
import net.i2p.data.i2np.DatabaseStoreMessage;
import net.i2p.data.i2np.DeliveryStatusMessage;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.OutNetMessage;
import net.i2p.router.Router;
@ -440,7 +442,41 @@ public class EstablishmentManager {
_transport.inboundConnectionReceived();
_context.statManager().addRateData("udp.inboundEstablishTime", state.getLifetime(), 0);
sendOurInfo(peer, true);
sendInboundComplete(peer);
}
/**
* dont send our info immediately, just send a small data packet, and 5-10s later,
* if the peer isnt shitlisted, *then* send them our info. this will help kick off
* the oldnet
*/
private void sendInboundComplete(PeerState peer) {
SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 10*1000);
if (_log.shouldLog(Log.INFO))
_log.info("Completing to the peer after confirm: " + peer);
DeliveryStatusMessage dsm = new DeliveryStatusMessage(_context);
dsm.setArrival(Router.NETWORK_ID); // overloaded, sure, but future versions can check this
dsm.setMessageExpiration(dsm.getArrival()+10*1000);
dsm.setMessageId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
_transport.send(dsm, peer);
}
private class PublishToNewInbound implements SimpleTimer.TimedEvent {
private PeerState _peer;
public PublishToNewInbound(PeerState peer) { _peer = peer; }
public void timeReached() {
Hash peer = _peer.getRemotePeer();
if ((peer != null) && (!_context.shitlist().isShitlisted(peer))) {
// ok, we are fine with them, send them our latest info
if (_log.shouldLog(Log.INFO))
_log.info("Publishing to the peer after confirm plus delay (without shitlist): " + peer.toBase64());
sendOurInfo(_peer, true);
} else {
// nuh uh. fuck 'em.
if (_log.shouldLog(Log.WARN))
_log.warn("NOT publishing to the peer after confirm plus delay (WITH shitlist): " + (peer != null ? peer.toBase64() : "unknown"));
}
_peer = null;
}
}
/**

View File

@ -58,6 +58,9 @@ public class PacketHandler {
_context.statManager().createRateStat("udp.droppedInvalidUnkown", "How old the packet we dropped due to invalidity (unkown type) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidReestablish", "How old the packet we dropped due to invalidity (doesn't use existing key, not an establishment) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidEstablish", "How old the packet we dropped due to invalidity (establishment, bad key) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidEstablish.inbound", "How old the packet we dropped due to invalidity (even though we have an active inbound establishment with the peer) was", "udp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidEstablish.outbound", "How old the packet we dropped due to invalidity (even though we have an active outbound establishment with the peer) was", "udp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidEstablish.new", "How old the packet we dropped due to invalidity (even though we do not have any active establishment with the peer) was", "udp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidInboundEstablish", "How old the packet we dropped due to invalidity (inbound establishment, bad key) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidSkew", "How skewed the packet we dropped due to invalidity (valid except bad skew) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.packetDequeueTime", "How long it takes the UDPReader to pull a packet off the inbound packet queue (when its slow)", "udp", new long[] { 10*60*1000, 60*60*1000 });
@ -90,6 +93,13 @@ public class PacketHandler {
}
return rv.toString();
}
/** the packet is from a peer we are establishing an outbound con to, but failed validation, so fallback */
private static final short OUTBOUND_FALLBACK = 1;
/** the packet is from a peer we are establishing an inbound con to, but failed validation, so fallback */
private static final short INBOUND_FALLBACK = 2;
/** the packet is not from anyone we know */
private static final short NEW_PEER = 3;
private class Handler implements Runnable {
private UDPPacketReader _reader;
@ -106,6 +116,7 @@ public class PacketHandler {
UDPPacket packet = _endpoint.receive();
_state = 3;
if (packet == null) continue; // keepReading is probably false...
packet.received();
if (_log.shouldLog(Log.INFO))
_log.info("Received the packet " + packet);
@ -202,7 +213,7 @@ public class PacketHandler {
_log.debug("Packet received is not for an inbound or outbound establishment");
// ok, not already known establishment, try as a new one
_state = 15;
receivePacket(reader, packet);
receivePacket(reader, packet, NEW_PEER);
}
}
} else {
@ -264,13 +275,24 @@ public class PacketHandler {
_state = 26;
}
private void receivePacket(UDPPacketReader reader, UDPPacket packet) {
private void receivePacket(UDPPacketReader reader, UDPPacket packet, short peerType) {
_state = 27;
boolean isValid = packet.validate(_transport.getIntroKey());
if (!isValid) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid introduction packet received: " + packet, new Exception("path"));
_context.statManager().addRateData("udp.droppedInvalidEstablish", packet.getLifetime(), packet.getExpiration());
switch (peerType) {
case INBOUND_FALLBACK:
_context.statManager().addRateData("udp.droppedInvalidEstablish.inbound", packet.getLifetime(), packet.getTimeSinceReceived());
break;
case OUTBOUND_FALLBACK:
_context.statManager().addRateData("udp.droppedInvalidEstablish.outbound", packet.getLifetime(), packet.getTimeSinceReceived());
break;
case NEW_PEER:
_context.statManager().addRateData("udp.droppedInvalidEstablish.new", packet.getLifetime(), packet.getTimeSinceReceived());
break;
}
_state = 28;
return;
} else {
@ -322,7 +344,7 @@ public class PacketHandler {
// ok, we couldn't handle it with the established stuff, so fall back
// on earlier state packets
_state = 34;
receivePacket(reader, packet);
receivePacket(reader, packet, INBOUND_FALLBACK);
} else {
_context.statManager().addRateData("udp.droppedInvalidInboundEstablish", packet.getLifetime(), packet.getExpiration());
}
@ -373,7 +395,7 @@ public class PacketHandler {
// ok, we couldn't handle it with the established stuff, so fall back
// on earlier state packets
_state = 41;
receivePacket(reader, packet);
receivePacket(reader, packet, OUTBOUND_FALLBACK);
_state = 42;
}
@ -413,7 +435,7 @@ public class PacketHandler {
_state = 45;
RemoteHostId from = packet.getRemoteHost();
_state = 46;
switch (reader.readPayloadType()) {
case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST:
_state = 47;

View File

@ -47,6 +47,7 @@ public class UDPReceiver {
_context.statManager().createRateStat("udp.droppedInboundProbabalistically", "How many packet we drop probabalistically (to simulate failures)", "udp", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.acceptedInboundProbabalistically", "How many packet we accept probabalistically (to simulate failures)", "udp", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.receiveHolePunch", "How often we receive a NAT hole punch", "udp", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.ignorePacketFromDroplist", "Packet lifetime for those dropped on the drop list", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
}
public void startup() {
@ -124,6 +125,15 @@ public class UDPReceiver {
private final int doReceive(UDPPacket packet) {
if (_log.shouldLog(Log.INFO))
_log.info("Received: " + packet);
RemoteHostId from = packet.getRemoteHost();
if (_transport.isInDropList(from)) {
if (_log.shouldLog(Log.INFO))
_log.info("Ignoring packet from the drop-listed peer: " + from);
_context.statManager().addRateData("udp.ignorePacketFromDroplist", packet.getLifetime(), 0);
packet.release();
return 0;
}
packet.enqueue();
boolean rejected = false;

View File

@ -78,6 +78,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
/** shared slow bid for unconnected peers when we want to prefer UDP */
private TransportBid _slowPreferredBid;
/** list of RemoteHostId for peers whose packets we want to drop outright */
private List _dropList;
private static final int DROPLIST_PERIOD = 10*60*1000;
private static final int MAX_DROPLIST_SIZE = 256;
public static final String STYLE = "SSU";
public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
@ -124,6 +130,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_log = ctx.logManager().getLog(UDPTransport.class);
_peersByIdent = new HashMap(128);
_peersByRemoteHost = new HashMap(128);
_dropList = new ArrayList(256);
_endpoint = null;
TimedWeightedPriorityMessageQueue mq = new TimedWeightedPriorityMessageQueue(ctx, PRIORITY_LIMITS, PRIORITY_WEIGHT, this);
@ -572,11 +579,25 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
+ " because they are in the wrong net");
}
*/
_context.shitlist().shitlistRouter(dsm.getRouterInfo().getIdentity().calculateHash(), "Part of the wrong network");
dropPeer(dsm.getRouterInfo().getIdentity().calculateHash());
Hash peerHash = dsm.getRouterInfo().getIdentity().calculateHash();
PeerState peer = getPeerState(peerHash);
if (peer != null) {
RemoteHostId remote = peer.getRemoteHostId();
boolean added = false;
synchronized (_dropList) {
if (!_dropList.contains(remote)) {
while (_dropList.size() > MAX_DROPLIST_SIZE)
_dropList.remove(0);
_dropList.add(remote);
added = true;
}
}
if (added) SimpleTimer.getInstance().addEvent(new RemoveDropList(remote), DROPLIST_PERIOD);
}
_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network");
dropPeer(peerHash);
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping the peer " + dsm.getRouterInfo().getIdentity().calculateHash().toBase64()
+ " because they are in the wrong net");
_log.warn("Dropping the peer " + peerHash.toBase64() + " because they are in the wrong net");
return;
} else {
if (dsm.getRouterInfo() != null) {
@ -597,6 +618,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
peer.expireInboundMessages();
}
private class RemoveDropList implements SimpleTimer.TimedEvent {
private RemoteHostId _peer;
public RemoveDropList(RemoteHostId peer) { _peer = peer; }
public void timeReached() {
synchronized (_dropList) {
_dropList.remove(_peer);
}
}
}
public boolean isInDropList(RemoteHostId peer) { synchronized (_dropList) { return _dropList.contains(peer); } }
void dropPeer(Hash peer) {
PeerState state = getPeerState(peer);