diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java index b9388bda1..00f9f42fd 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java @@ -26,6 +26,7 @@ import java.util.*; import net.i2p.util.I2PThread; import net.i2p.util.Log; +import net.i2p.util.SimpleTimer; class PeerConnectionOut implements Runnable { @@ -94,6 +95,8 @@ class PeerConnectionOut implements Runnable // being send even if we get unchoked a little later. // (Since we will resent them anyway in that case.) // And remove piece messages if we are choking. + + // this should get fixed for starvation Iterator it = sendQueue.iterator(); while (m == null && it.hasNext()) { @@ -177,10 +180,30 @@ class PeerConnectionOut implements Runnable */ private void addMessage(Message m) { + SimpleTimer.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT); synchronized(sendQueue) { sendQueue.add(m); - sendQueue.notify(); + sendQueue.notifyAll(); + } + } + + /** remove messages not sent in 30s */ + private static final int SEND_TIMEOUT = 30*1000; + private class RemoveTooSlow implements SimpleTimer.TimedEvent { + private Message _m; + public RemoveTooSlow(Message m) { + _m = m; + } + + public void timeReached() { + boolean removed = false; + synchronized (sendQueue) { + removed = sendQueue.remove(_m); + sendQueue.notifyAll(); + } + if (removed) + _log.info("Took too long to send " + _m + " to " + peer); } } @@ -206,6 +229,7 @@ class PeerConnectionOut implements Runnable removed = true; } } + sendQueue.notifyAll(); } return removed; } diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index 09d438bc2..3b5f4c4fb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -28,6 +28,7 @@ import org.klomp.snark.bencode.*; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PServerSocket; +import net.i2p.util.I2PThread; /** * Main Snark program startup class. @@ -87,12 +88,26 @@ public class Snark // String indicating main activity String activity = "Not started"; + private static class OOMListener implements I2PThread.OOMEventListener { + public void outOfMemory(OutOfMemoryError err) { + try { + err.printStackTrace(); + I2PSnarkUtil.instance().debug("OOM in the snark", Snark.ERROR, err); + } catch (Throwable t) { + System.out.println("OOM in the OOM"); + } + System.exit(0); + } + + } + public static void main(String[] args) { System.out.println(copyright); System.out.println(); if ( (args.length > 0) && ("--config".equals(args[0])) ) { + I2PThread.addOOMEventListener(new OOMListener()); SnarkManager sm = SnarkManager.instance(); if (args.length > 1) sm.loadConfig(args[1]); diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 31508cc1b..1f5183a8a 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -281,10 +281,10 @@ public class SnarkManager implements Snark.CompleteListener { fis.close(); fis = null; - List files = info.getFiles(); - if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { + String rejectMessage = locked_validateTorrent(info); + if (rejectMessage != null) { sfile.delete(); - addMessage("Too many files in " + sfile.getName() + " (" + files.size() + "), deleting it"); + addMessage(rejectMessage); return; } else { torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath()); @@ -313,6 +313,28 @@ public class SnarkManager implements Snark.CompleteListener { } } + private String locked_validateTorrent(MetaInfo info) throws IOException { + List files = info.getFiles(); + if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { + return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it"; + } else if (info.getPieces() <= 0) { + return "No pieces in " + info.getName() + "? deleting it"; + } else if (info.getPieceLength(0) > 1024*1024) { + return "Pieces are too large in " + info.getName() + " (" + info.getPieceLength(0)/1024 + "KB, deleting it"; + } else if (info.getTotalLength() > 10*1024*1024*1024l) { + System.out.println("torrent info: " + info.toString()); + List lengths = info.getLengths(); + if (lengths != null) + for (int i = 0; i < lengths.size(); i++) + System.out.println("File " + i + " is " + lengths.get(i) + " long"); + + return "Torrents larger than 10GB are not supported yet (because we're paranoid): " + info.getName() + ", deleting it"; + } else { + // ok + return null; + } + } + /** * Stop the torrent, leaving it on the list of torrents unless told to remove it */ diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 4594ac9de..8d2967c59 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -172,6 +172,10 @@ public class I2PSnarkServlet extends HttpServlet { if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) { _manager.stopTorrent(name, true); // should we delete the torrent file? + // yeah, need to, otherwise it'll get autoadded again (at the moment + File f = new File(name); + f.delete(); + _manager.addMessage("Torrent file deleted: " + f.getAbsolutePath()); break; } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index a9ba96284..b9f6fd342 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -386,6 +386,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } else { request = request.substring(pos + 1); pos = request.indexOf("/"); + if (pos < 0) { + l.log("Invalid request url [" + request + "]"); + if (out != null) { + out.write(ERR_REQUEST_DENIED); + out.write("

Generated on: ".getBytes()); + out.write(new Date().toString().getBytes()); + out.write("\n".getBytes()); + out.flush(); + } + s.close(); + return; + } destination = request.substring(0, pos); line = method + " " + request.substring(pos); } diff --git a/history.txt b/history.txt index 755fb904c..ba8b1e40d 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,10 @@ -$Id: history.txt,v 1.359 2005/12/16 06:01:20 jrandom Exp $ +$Id: history.txt,v 1.360 2005/12/16 18:18:56 jrandom Exp $ + +2005-12-16 jrandom + * Added some I2PSnark sanity checks, an OOMListener when running + standalone, and a guard against keeping memory tied up indefinitely. + * Sanity check on the watchdog (thanks zzz!) + * Handle invalid HTTP requests in I2PTunnel a little better 2005-12-16 jrandom * Moved I2PSnark from using Threads to I2PThreads, so we handle OOMs diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 576db958e..ff54a0c3e 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.310 $ $Date: 2005/12/13 16:56:42 $"; + public final static String ID = "$Revision: 1.311 $ $Date: 2005/12/14 04:32:51 $"; public final static String VERSION = "0.6.1.7"; - public final static long BUILD = 4; + public final static long BUILD = 5; 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/RouterWatchdog.java b/router/java/src/net/i2p/router/RouterWatchdog.java index f8f78a763..c5dafbbe8 100644 --- a/router/java/src/net/i2p/router/RouterWatchdog.java +++ b/router/java/src/net/i2p/router/RouterWatchdog.java @@ -91,7 +91,14 @@ class RouterWatchdog implements Runnable { public void monitorRouter() { boolean ok = verifyJobQueueLiveliness(); // If we aren't connected to the network that's why there's nobody to talk to - int netErrors = (int) _context.statManager().getRate("udp.sendException").getRate(60*1000).getLastEventCount(); + long netErrors = 0; + RateStat rs = _context.statManager().getRate("udp.sendException"); + if (rs != null) { + Rate r = rs.getRate(60*1000); + if (r != null) + netErrors = r.getLastEventCount(); + } + ok = ok && (verifyClientLiveliness() || netErrors >= 5); if (!ok) {