diff --git a/core/java/src/net/i2p/stat/Rate.java b/core/java/src/net/i2p/stat/Rate.java index adf7c57eb..d4cc13796 100644 --- a/core/java/src/net/i2p/stat/Rate.java +++ b/core/java/src/net/i2p/stat/Rate.java @@ -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; diff --git a/core/java/src/net/i2p/util/DecayingBloomFilter.java b/core/java/src/net/i2p/util/DecayingBloomFilter.java index b76e99408..d2d7fd722 100644 --- a/core/java/src/net/i2p/util/DecayingBloomFilter.java +++ b/core/java/src/net/i2p/util/DecayingBloomFilter.java @@ -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; } diff --git a/history.txt b/history.txt index a3ef04db8..a6f97a3e1 100644 --- a/history.txt +++ b/history.txt @@ -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) diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index e82754069..6577dad77 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -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); } } diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f92b648cb..8294fe706 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -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); diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index 84e17c6d6..4a37853aa 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -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; + } } /** diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index 43e978bfb..882054f1b 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -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; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java index 34a660d27..61064162e 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java @@ -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; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index bae859af5..6073dec1c 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -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);