diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 9976d44d94c01af043cc8638be0969e0db0f4e81..67ac95e55a137549976417db82ac9e4a1744d817 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -240,15 +240,19 @@ public class PeerCoordinator implements PeerListener } } - /** reduce max if huge pieces to keep from ooming */ + /** + * Reduce max if huge pieces to keep from ooming + * Todo: should we only reduce when leeching? + * @return 512K: 16; 1M: 11; 2M: 8 + */ private int getMaxConnections() { int size = metainfo.getPieceLength(0); int max = _util.getMaxConnections(); - if (size <= 1024*1024) + if (size <= 512*1024) return max; - if (size <= 2*1024*1024) - return (max + 1) / 2; - return (max + 3) / 4; + if (size <= 1024*1024) + return (max + max + 2) / 3; + return (max + 1) / 2; } public boolean halted() { return halted; } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 378cd8758c94dbed20080b2fc6e2fd40c1ffe4b0..2fa597ce5135c0c78ee367b0abdfc37c0a5dc347 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -152,7 +152,16 @@ class PeerState // XXX - Check for weird bitfield and disconnect? bitfield = new BitField(bitmap, metainfo.getPieces()); } - setInteresting(listener.gotBitField(peer, bitfield)); + boolean interest = listener.gotBitField(peer, bitfield); + setInteresting(interest); + if (bitfield.complete() && !interest) { + // They are seeding and we are seeding, + // why did they contact us? (robert) + // Dump them quick before we send our whole bitmap + if (_log.shouldLog(Log.WARN)) + _log.warn("Disconnecting seed that connects to seeds" + peer); + peer.disconnect(true); + } } void requestMessage(int piece, int begin, int length) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java index d804e384c7aab156d477b4ad11ef669c3c5e7fbf..f6aa9adb4be6259d445fe663558564064f26e677 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -259,8 +259,7 @@ public class PluginStarter implements Runnable { String current = ctx.getProperty(CSSHelper.PROP_THEME_NAME); for (int i = 0; i < tfiles.length; i++) { String name = tfiles[i].getName(); - if (tfiles[i].isDirectory() && (!name.equals("images")) && (!name.equals("classic")) && - (!name.equals("dark")) && (!name.equals("light")) && (!name.equals("midnight"))) { + if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i]))) { ctx.router().removeConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name); if (name.equals(current)) ctx.router().setConfigSetting(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java index a3f691ecebcbff7980af7d2436a1ef432a058758..ea4e1f069c8594002537cb1b8ee0375dbdf11099 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java @@ -386,8 +386,10 @@ public class ConnectionOptions extends I2PSocketOptionsImpl { private static final double RTT_DAMPENING = 0.875; public void updateRTT(int measuredValue) { + // the rttDev calculation matches that recommended in RFC 2988 (beta = 1/4) _rttDev = _rttDev + (int)(0.25d*(Math.abs(measuredValue-_rtt)-_rttDev)); int smoothed = (int)(RTT_DAMPENING*_rtt + (1-RTT_DAMPENING)*measuredValue); + // K = 4 _rto = smoothed + (_rttDev<<2); if (_rto < Connection.MIN_RESEND_DELAY) _rto = (int)Connection.MIN_RESEND_DELAY; diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java index b9ebbb7d24bd12cede12dce51d2aef7ec5447ab2..5292b5f09f6ef29a53fe2d1954738469fef41afa 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java @@ -328,7 +328,19 @@ public class ConnectionPacketHandler { } long lowest = con.getHighestAckedThrough(); - if (lowest >= con.getCongestionWindowEnd()) { + // RFC 2581 + // Why wait until we get a whole cwin to start updating the window? + // That means we don't start increasing the window until after 1 RTT. + // And whether we increase the window or not (probably not since 1/N), + // we reset the CongestionWindowEnd and have to wait another RTT. + // So we add the acked > 1 and UnackedPacketsSent > 0 cases, + // so we almost always go through the window adjustment code, + // unless we're just sending a single packet now and then. + // This keeps the window size from going sky-high from ping traffic alone. + // Since we don't adjust the window down after idle? (RFC 2581 sec. 4.1) + if (lowest >= con.getCongestionWindowEnd() || + acked > 1 || + con.getUnackedPacketsSent() > 0) { // new packet that ack'ed uncongested data, or an empty ack int oldWindow = con.getOptions().getWindowSize(); int newWindowSize = oldWindow; @@ -352,11 +364,12 @@ public class ConnectionPacketHandler { newWindowSize += acked / factor; if (_log.shouldLog(Log.DEBUG)) _log.debug("slow start acks = " + acked + " for " + con); - } else if (trend < 0) { - // rtt is shrinking, so lets increment the cwin - newWindowSize++; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("trend < 0 for " + con); + // this is too fast since we mostly disabled the CongestionWindowEnd test above + //} else if (trend < 0) { + // // rtt is shrinking, so lets increment the cwin + // newWindowSize++; + // if (_log.shouldLog(Log.DEBUG)) + // _log.debug("trend < 0 for " + con); } else { // congestion avoidance // linear growth - increase window 1/N per RTT @@ -368,6 +381,10 @@ public class ConnectionPacketHandler { if (_log.shouldLog(Log.DEBUG)) _log.debug("cong. avoid acks = " + acked + " for " + con); } + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("No change to window: " + con.getOptions().getWindowSize() + + " congested? " + congested + " acked: " + acked + " resends: " + numResends); } if (newWindowSize <= 0) @@ -380,6 +397,11 @@ public class ConnectionPacketHandler { _log.debug("New window size " + newWindowSize + "/" + oldWindow + "/" + con.getOptions().getWindowSize() + " congestionSeenAt: " + con.getLastCongestionSeenAt() + " (#resends: " + numResends + ") for " + con); + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("No change to window: " + con.getOptions().getWindowSize() + + " highestAckedThrough: " + lowest + " congestionWindowEnd: " + con.getCongestionWindowEnd() + + " acked: " + acked + " unacked: " + con.getUnackedPacketsSent()); } con.windowAdjusted(); diff --git a/history.txt b/history.txt index 4a6e2d8ed7db0f92e9792ff3425d36f9f6d4c2fa..0b07ff3327fcbd96a348362b22c63aa84fa55955 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,16 @@ +2010-04-10 zzz + * i2psnark: + - Disconnect seeds that connect to a seed + - Lower per-torrent conn limits for large pieces + * Startup: + - Don't die horribly if there is a router.info file + but no router.keys file + http://forum.i2p/viewtopic.php?t=4424 + - Log tweaks + * Streaming: + - Fix the window size increment logic so it + does it much more often + 2010-04-08 zzz * Key Manager: Hopefully avoid some races at startup http://forum.i2p/viewtopic.php?t=4424 diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index fecba78d6973d87e9930d631de787e05fec2a510..a6204817e3d9e640632604f1432a96320e1992ce 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/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java index 5fbce84cd6a06133c6027ad6da0c47ab0f3c0cd5..459cd0fb3ae2a8d07959a34cd208efb562cd1124 100644 --- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java @@ -98,9 +98,9 @@ public class CreateRouterInfoJob extends JobImpl { _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]"); } catch (DataFormatException dfe) { - _log.error("Error building the new router information", dfe); + _log.log(Log.CRIT, "Error building the new router information", dfe); } catch (IOException ioe) { - _log.error("Error writing out the new router information", ioe); + _log.log(Log.CRIT, "Error writing out the new router information", ioe); } finally { if (fos1 != null) try { fos1.close(); } catch (IOException ioe) {} if (fos2 != null) try { fos2.close(); } catch (IOException ioe) {} diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java index f3428c4474886f08dc6a8b9edca93cf5fcf6f086..94b4f1d2eda8bc2227827cd91ae2299b4ba6c48a 100644 --- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java @@ -68,11 +68,18 @@ public class LoadRouterInfoJob extends JobImpl { FileInputStream fis1 = null; FileInputStream fis2 = null; try { - if (_infoExists) { + // if we have a routerinfo but no keys, things go bad in a hurry: + // CRIT ...rkdb.PublishLocalRouterInfoJob: Internal error - signing private key not known? rescheduling publish for 30s + // CRIT net.i2p.router.Router : Internal error - signing private key not known? wtf + // CRIT ...sport.udp.EstablishmentManager: Error in the establisher java.lang.NullPointerException + // at net.i2p.router.transport.udp.PacketBuilder.buildSessionConfirmedPacket(PacketBuilder.java:574) + // so pretend the RI isn't there if there is no keyfile + if (_infoExists && _keysExist) { fis1 = new FileInputStream(rif); info = new RouterInfo(); info.readBytes(fis1); _log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses"); + _us = info; } if (_keysExist) { @@ -91,17 +98,15 @@ public class LoadRouterInfoJob extends JobImpl { getContext().keyManager().setPublicKey(pubkey); //info.getIdentity().getPublicKey()); getContext().keyManager().setSigningPublicKey(signingPubKey); // info.getIdentity().getSigningPublicKey()); } - - _us = info; } catch (IOException ioe) { - _log.error("Error reading the router info from " + rif.getAbsolutePath() + " and the keys from " + rkf.getAbsolutePath(), ioe); + _log.log(Log.CRIT, "Error reading the router info from " + rif.getAbsolutePath() + " and the keys from " + rkf.getAbsolutePath(), ioe); _us = null; rif.delete(); rkf.delete(); _infoExists = false; _keysExist = false; } catch (DataFormatException dfe) { - _log.error("Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe); + _log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe); _us = null; rif.delete(); rkf.delete(); diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java index fda82de8e595e3a84fb3a6999406de0c7995f27a..e3daf60ea44d7fec76f55b3b11eef195c44d1936 100644 --- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java @@ -107,7 +107,7 @@ public class RebuildRouterInfoJob extends JobImpl { ident.setSigningPublicKey(signingPubKey); info.setIdentity(ident); } catch (Exception e) { - _log.error("Error reading in the key data from " + keyFile.getAbsolutePath(), e); + _log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e); if (fis != null) try { fis.close(); } catch (IOException ioe) {} fis = null; keyFile.delete(); @@ -129,7 +129,7 @@ public class RebuildRouterInfoJob extends JobImpl { info.sign(getContext().keyManager().getSigningPrivateKey()); } catch (DataFormatException dfe) { - _log.error("Error rebuilding the new router info", dfe); + _log.log(Log.CRIT, "Error rebuilding the new router info", dfe); return; } @@ -138,9 +138,9 @@ public class RebuildRouterInfoJob extends JobImpl { fos = new FileOutputStream(infoFile); info.writeBytes(fos); } catch (DataFormatException dfe) { - _log.error("Error rebuilding the router information", dfe); + _log.log(Log.CRIT, "Error rebuilding the router information", dfe); } catch (IOException ioe) { - _log.error("Error writing out the rebuilt router information", ioe); + _log.log(Log.CRIT, "Error writing out the rebuilt router information", ioe); } finally { if (fos != null) try { fos.close(); } catch (IOException ioe) {} } 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 91c23b4447a79135169bd3cb3e7bd47f661ae588..64e1bdea2df425b95342d72aa22c55eebe1ea061 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -699,6 +699,7 @@ public class EstablishmentManager { // signs if we havent signed yet state.prepareSessionConfirmed(); + // BUG - handle null return UDPPacket packets[] = _builder.buildSessionConfirmedPackets(state, _context.router().getRouterInfo().getIdentity()); if (_log.shouldLog(Log.DEBUG)) diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index fa01bc026f9e776d2504492ad30d5da62a318305..6e3738f306d117fec298375bdbcbf93f415526c8 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -348,6 +348,8 @@ public class OutboundEstablishState { DataHelper.toLong(signed, off, 4, _receivedRelayTag); off += 4; DataHelper.toLong(signed, off, 4, _sentSignedOnTime); + // BUG - if SigningPrivateKey is null, _sentSignature will be null, leading to NPE later + // should we throw something from here? _sentSignature = _context.dsa().sign(signed, _context.keyManager().getSigningPrivateKey()); } diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 26b82e66753c62dd444858b21cf0e1303ad0c9b7..4b16d078dae7bda704376d642aa9e60045389086 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -512,6 +512,10 @@ public class PacketBuilder { * encrypting it as necessary. * * @return ready to send packets, or null if there was a problem + * + * TODO: doesn't really return null, and caller doesn't handle null return + * (null SigningPrivateKey should cause this?) + * Should probably return null if buildSessionConfirmedPacket() turns null for any fragment */ public UDPPacket[] buildSessionConfirmedPackets(OutboundEstablishState state, RouterIdentity ourIdentity) { byte identity[] = ourIdentity.toByteArray(); @@ -593,6 +597,7 @@ public class PacketBuilder { off++; } + // BUG: NPE here if null signature System.arraycopy(state.getSentSignature().getData(), 0, data, off, Signature.SIGNATURE_BYTES); packet.getPacket().setLength(off + Signature.SIGNATURE_BYTES); authenticate(packet, state.getCipherKey(), state.getMACKey());