diff --git a/history.txt b/history.txt index 8d9d2763ef..21e8c6c4d1 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,14 @@ +2012-10-06 zzz + * configlogging.jsp: Fix IAE + * error500.jsp: Fix whitespace + * i2psnark: + - Add allocating and checking indications + - Add bandwidth message at startup + - More checks at torrent creation + * SSU: + - Throttle outbound destroys on shutdown + - Limit outbound introduction offers + 2012-10-05 zzz * configservice.jsp: Add GC button * DataHelper: Sanity checks in storeProps(), use diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index fecba78d69..a6204817e3 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -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 = 7; + public final static long BUILD = 8; /** for example "-test" */ public final static String EXTRA = ""; 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 8de50e9cb5..5a43bbb889 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -21,7 +21,6 @@ import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.OutNetMessage; import net.i2p.router.Router; import net.i2p.router.RouterContext; -import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.transport.crypto.DHSessionKeyBuilder; import static net.i2p.router.transport.udp.InboundEstablishState.InboundState.*; import static net.i2p.router.transport.udp.OutboundEstablishState.OutboundState.*; @@ -455,14 +454,9 @@ class EstablishmentManager { } if (isNew) { - // we don't expect inbound connections when hidden, but it could happen - // Don't offer if we are approaching max connections. While Relay Intros do not - // count as connections, we have to keep the connection to this peer up longer if - // we are offering introductions. // Don't offer to relay to privileged ports. - if ((!_context.router().isHidden()) && (!_transport.introducersRequired()) && _transport.haveCapacity() && - state.getSentPort() >= 1024 && - !((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled()) { + // TODO if already we have their RI, only offer if they need it (no 'C' cap) + if (_transport.canIntroduce() && state.getSentPort() >= 1024) { // ensure > 0 long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE); state.setSentRelayTag(tag); @@ -816,29 +810,10 @@ class EstablishmentManager { /** the relay tag is a 4-byte field in the protocol */ public static final long MAX_TAG_VALUE = 0xFFFFFFFFl; + /** + * This may be called more than once + */ private void sendCreated(InboundEstablishState state) { - long now = _context.clock().now(); - // This is usually handled in receiveSessionRequest() above, except, I guess, - // if the session isn't new and we are going through again. - // Don't offer if we are approaching max connections (see comments above) - // Also don't offer if we are floodfill, as this extends the max idle time - // and we will have lots of incoming conns - if ((!_context.router().isHidden()) && (!_transport.introducersRequired()) && _transport.haveCapacity() && - !((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled()) { - // offer to relay - // (perhaps we should check our bw usage and/or how many peers we are - // already offering introducing?) - if (state.getSentRelayTag() == 0) { - // ensure > 0 - state.setSentRelayTag(1 + _context.random().nextLong(MAX_TAG_VALUE)); - } else { - // don't change it, since we've already prepared our sig - } - } else { - // don't offer to relay - state.setSentRelayTag(0); - } - if (_log.shouldLog(Log.DEBUG)) _log.debug("Send created to: " + state); diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index c5eef5f29e..dba4cb32d8 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -43,10 +43,10 @@ class IntroductionManager { private static final int MAX_INBOUND = 20; /** - * TODO this should be enforced in EstablishmentManager, it isn't now. + * This is enforced in EstablishmentManager * @since 0.8.11 */ - private static final int MAX_OUTBOUND = 100; + public static final int MAX_OUTBOUND = 100; /** Max one per target in this time */ private static final long PUNCH_CLEAN_TIME = 5*1000; @@ -208,6 +208,14 @@ class IntroductionManager { int introducerCount() { return _inbound.size(); } + + /** + * @return number of peers we have volunteered to introduce + * @since 0.9.3 + */ + int introducedCount() { + return _outbound.size(); + } /** * We are Charlie and we got this from Bob. 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 8e04d58665..ea81096b9c 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -32,6 +32,7 @@ import net.i2p.router.CommSystemFacade; import net.i2p.router.OutNetMessage; import net.i2p.router.Router; import net.i2p.router.RouterContext; +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.transport.Transport; import net.i2p.router.transport.TransportBid; import net.i2p.router.transport.TransportImpl; @@ -1214,20 +1215,33 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } /** - * Send a session destroy message to everybody - * BLOCKING if OB queue is full. + * Send a session destroy message to everybody. + * BLOCKING for at least 1 sec per 1K peers, more if BW is very low or if OB queue is full. * * @since 0.8.9 */ private void destroyAll() { _endpoint.clearOutbound(); int howMany = _peersByIdent.size(); + // use no more than 1/4 of configured bandwidth + final int burst = 8; + int pps = Math.max(48, (_context.bandwidthLimiter().getOutboundKBytesPerSecond() * 1000 / 4) / 48); + int burstps = pps / burst; + // max of 1000 pps + int toSleep = Math.max(8, (1000 / burstps)); + int count = 0; if (_log.shouldLog(Log.WARN)) _log.warn("Sending destroy to : " + howMany + " peers"); for (PeerState peer : _peersByIdent.values()) { sendDestroy(peer); + // 1000 per second * 48 bytes = 400 KBps + if ((++count) % burst == 0) { + try { + Thread.sleep(toSleep); + } catch (InterruptedException ie) {} + } } - int toSleep = Math.min(howMany / 3, 750); + toSleep = Math.min(howMany / 3, 750); if (toSleep > 0) { try { Thread.sleep(toSleep); @@ -1595,6 +1609,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } + /** + * For EstablishmentManager + * @since 0.9.3 + */ + boolean canIntroduce() { + // we don't expect inbound connections when hidden, but it could happen + // Don't offer if we are approaching max connections. While Relay Intros do not + // count as connections, we have to keep the connection to this peer up longer if + // we are offering introductions. + return + (!_context.router().isHidden()) && + (!introducersRequired()) && + haveCapacity() && + (!((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled()) && + _introManager.introducedCount() < IntroductionManager.MAX_OUTBOUND && + _introManager.introducedCount() < getMaxConnections() / 4; + } + /** default true */ private boolean allowDirectUDP() { return _context.getBooleanPropertyDefaultTrue(PROP_ALLOW_DIRECT);