2005-12-16 jrandom
* Refuse torrents with too many files (128), avoiding ulimit errors. * Remove an fd leak in I2PSnark * Further I2PSnark web UI cleanup
This commit is contained in:
@ -33,6 +33,7 @@ public class PeerCoordinator implements PeerListener
|
||||
private final Log _log = new Log(PeerCoordinator.class);
|
||||
final MetaInfo metainfo;
|
||||
final Storage storage;
|
||||
final Snark snark;
|
||||
|
||||
// package local for access by CheckDownLoadersTask
|
||||
final static long CHECK_PERIOD = 20*1000; // 20 seconds
|
||||
@ -70,12 +71,13 @@ public class PeerCoordinator implements PeerListener
|
||||
public int trackerSeenPeers = 0;
|
||||
|
||||
public PeerCoordinator(byte[] id, MetaInfo metainfo, Storage storage,
|
||||
CoordinatorListener listener)
|
||||
CoordinatorListener listener, Snark torrent)
|
||||
{
|
||||
this.id = id;
|
||||
this.metainfo = metainfo;
|
||||
this.storage = storage;
|
||||
this.listener = listener;
|
||||
this.snark = torrent;
|
||||
|
||||
// Make a list of pieces
|
||||
wantedPieces = new ArrayList();
|
||||
@ -400,8 +402,9 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
Snark.fatal("Error reading storage", ioe);
|
||||
return null; // Never reached.
|
||||
snark.stopTorrent();
|
||||
_log.error("Error reading the storage for " + metainfo.getName(), ioe);
|
||||
throw new RuntimeException("B0rked");
|
||||
}
|
||||
}
|
||||
|
||||
@ -476,7 +479,9 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
Snark.fatal("Error writing storage", ioe);
|
||||
snark.stopTorrent();
|
||||
_log.error("Error writing storage for " + metainfo.getName(), ioe);
|
||||
throw new RuntimeException("B0rked");
|
||||
}
|
||||
wantedPieces.remove(p);
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ public class Snark
|
||||
}
|
||||
|
||||
debug(meta.toString(), INFO);
|
||||
|
||||
|
||||
// When the metainfo torrent was created from an existing file/dir
|
||||
// it already exists.
|
||||
if (storage == null)
|
||||
@ -346,12 +346,15 @@ public class Snark
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
try { storage.close(); } catch (IOException ioee) {
|
||||
ioee.printStackTrace();
|
||||
}
|
||||
fatal("Could not create storage", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(id, meta, storage, clistener);
|
||||
coordinator = new PeerCoordinator(id, meta, storage, clistener, this);
|
||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||
set.add(coordinator);
|
||||
PeerAcceptor peeracceptor = new PeerAcceptor(set); //coordinator);
|
||||
@ -374,7 +377,7 @@ public class Snark
|
||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||
set.remove(coordinator);
|
||||
PeerCoordinator newCoord = new PeerCoordinator(coordinator.getID(), coordinator.getMetaInfo(),
|
||||
coordinator.getStorage(), coordinator.getListener());
|
||||
coordinator.getStorage(), coordinator.getListener(), this);
|
||||
set.add(newCoord);
|
||||
coordinator = newCoord;
|
||||
coordinatorChanged = true;
|
||||
@ -569,7 +572,7 @@ public class Snark
|
||||
/**
|
||||
* Aborts program abnormally.
|
||||
*/
|
||||
public static void fatal(String s)
|
||||
public void fatal(String s)
|
||||
{
|
||||
fatal(s, null);
|
||||
}
|
||||
@ -577,12 +580,13 @@ public class Snark
|
||||
/**
|
||||
* Aborts program abnormally.
|
||||
*/
|
||||
public static void fatal(String s, Throwable t)
|
||||
public void fatal(String s, Throwable t)
|
||||
{
|
||||
I2PSnarkUtil.instance().debug(s, ERROR, t);
|
||||
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
|
||||
//if (debug >= INFO && t != null)
|
||||
// t.printStackTrace();
|
||||
stopTorrent();
|
||||
throw new RuntimeException("die bart die");
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
monitor.start();
|
||||
}
|
||||
|
||||
private static final int MAX_MESSAGES = 10;
|
||||
private static final int MAX_MESSAGES = 5;
|
||||
public void addMessage(String message) {
|
||||
synchronized (_messages) {
|
||||
_messages.add(message);
|
||||
@ -243,6 +243,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
public Properties getConfig() { return _config; }
|
||||
|
||||
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
|
||||
private static final int MAX_FILES_PER_TORRENT = 128;
|
||||
|
||||
/** set of filenames that we are dealing with */
|
||||
public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } }
|
||||
/**
|
||||
@ -250,6 +253,14 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
*/
|
||||
public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } }
|
||||
public void addTorrent(String filename) {
|
||||
if (!I2PSnarkUtil.instance().connected()) {
|
||||
addMessage("Connecting to I2P");
|
||||
boolean ok = I2PSnarkUtil.instance().connect();
|
||||
if (!ok) {
|
||||
addMessage("Error connecting to I2P - check your I2CP settings");
|
||||
return;
|
||||
}
|
||||
}
|
||||
File sfile = new File(filename);
|
||||
try {
|
||||
filename = sfile.getCanonicalPath();
|
||||
@ -263,9 +274,31 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
synchronized (_snarks) {
|
||||
torrent = (Snark)_snarks.get(filename);
|
||||
if (torrent == null) {
|
||||
torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath());
|
||||
torrent.completeListener = this;
|
||||
_snarks.put(filename, torrent);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(sfile);
|
||||
MetaInfo info = new MetaInfo(fis);
|
||||
fis.close();
|
||||
fis = null;
|
||||
|
||||
List files = info.getFiles();
|
||||
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
|
||||
sfile.delete();
|
||||
addMessage("Too many files in " + sfile.getName() + " (" + files.size() + "), deleting it");
|
||||
return;
|
||||
} else {
|
||||
torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath());
|
||||
torrent.completeListener = this;
|
||||
_snarks.put(filename, torrent);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage());
|
||||
if (sfile.exists())
|
||||
sfile.delete();
|
||||
return;
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -330,6 +363,12 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
private class DirMonitor implements Runnable {
|
||||
public void run() {
|
||||
try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {}
|
||||
// the first message was a "We are starting up in 1m"
|
||||
synchronized (_messages) {
|
||||
if (_messages.size() == 1)
|
||||
_messages.remove(0);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
File dir = getDataDir();
|
||||
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath());
|
||||
|
@ -72,7 +72,8 @@ public class SnarkShutdown extends Thread
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
Snark.fatal("Couldn't properly close storage", ioe);
|
||||
I2PSnarkUtil.instance().debug("Couldn't properly close storage", Snark.ERROR, ioe);
|
||||
throw new RuntimeException("b0rking");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,10 +404,15 @@ public class Storage
|
||||
{
|
||||
for (int i = 0; i < rafs.length; i++)
|
||||
{
|
||||
synchronized(rafs[i])
|
||||
{
|
||||
rafs[i].close();
|
||||
}
|
||||
try {
|
||||
synchronized(rafs[i])
|
||||
{
|
||||
rafs[i].close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
I2PSnarkUtil.instance().debug("Error closing " + rafs[i], Snark.ERROR, ioe);
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,8 +254,9 @@ public class TrackerClient extends Thread
|
||||
throw new IOException("Error fetching " + s);
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
try {
|
||||
InputStream in = new FileInputStream(fetched);
|
||||
in = new FileInputStream(fetched);
|
||||
|
||||
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
|
||||
coordinator.getMetaInfo());
|
||||
@ -270,6 +271,7 @@ public class TrackerClient extends Thread
|
||||
interval = info.getInterval() * 1000;
|
||||
return info;
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
fetched.delete();
|
||||
}
|
||||
}
|
||||
|
@ -53,14 +53,18 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
// we want it to go to the base URI so we don't refresh with some funky action= value
|
||||
out.write("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + "\">\n");
|
||||
out.write(HEADER);
|
||||
out.write("<a href=\"" + req.getRequestURI() + "\">Refresh</a>\n");
|
||||
out.write("<textarea class=\"snarkMessages\" rows=\"2\" cols=\"100\" wrap=\"off\" >");
|
||||
|
||||
out.write("<table border=\"0\" width=\"100%\">\n");
|
||||
out.write("<tr><td width=\"5%\" class=\"snarkTitle\" valign=\"top\" align=\"left\">");
|
||||
out.write("I2PSnark<br />\n");
|
||||
out.write("<a href=\"" + req.getRequestURI() + "\" class=\"snarkRefresh\">Refresh</a>\n");
|
||||
out.write("</td><td width=\"95%\" class=\"snarkMessages\" valign=\"top\" align=\"left\"><pre>");
|
||||
List msgs = _manager.getMessages();
|
||||
for (int i = msgs.size()-1; i >= 0; i--) {
|
||||
String msg = (String)msgs.get(i);
|
||||
out.write(msg + "\n");
|
||||
}
|
||||
out.write("</textarea>\n");
|
||||
out.write("</pre></td></tr></table>\n");
|
||||
|
||||
out.write(TABLE_HEADER);
|
||||
|
||||
@ -302,6 +306,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
|
||||
boolean isRunning = !snark.stopped;
|
||||
boolean isValid = snark.meta != null;
|
||||
boolean singleFile = snark.meta.getFiles() == null;
|
||||
|
||||
String err = snark.coordinator.trackerProblems;
|
||||
int curPeers = snark.coordinator.getPeerCount();
|
||||
@ -330,7 +335,15 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write(statusString + "</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentName " + rowClass + "\">");
|
||||
out.write(filename + "</td>\n\t");
|
||||
|
||||
if (remaining == 0)
|
||||
out.write("<a href=\"file:///" + _manager.getDataDir().getAbsolutePath() + File.separatorChar + snark.meta.getName()
|
||||
+ "\" title=\"Download the completed file\">");
|
||||
out.write(filename);
|
||||
if (remaining == 0)
|
||||
out.write("</a>");
|
||||
out.write("</td>\n\t");
|
||||
|
||||
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
|
||||
if (remaining > 0) {
|
||||
out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB
|
||||
@ -380,7 +393,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
// not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve)
|
||||
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br />\n");
|
||||
out.write("<input type=\"submit\" value=\"Add torrent\" name=\"action\" /><br />\n");
|
||||
out.write("Alternately, you can copy .torrent files to " + _manager.getDataDir().getAbsolutePath() + "<br />\n");
|
||||
out.write("<span class=\"snarkAddInfo\">Alternately, you can copy .torrent files to " + _manager.getDataDir().getAbsolutePath() + "<br />\n");
|
||||
out.write("Removing that .torrent file will cause the torrent to stop.<br /></span>\n");
|
||||
out.write("</form>\n</span>\n");
|
||||
}
|
||||
|
||||
@ -466,12 +480,22 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
" font-size: 16pt;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
"}\n" +
|
||||
".snarkRefresh {\n" +
|
||||
" font-size: 10pt;\n" +
|
||||
"}\n" +
|
||||
".snarkMessages {\n" +
|
||||
" border: none;\n" +
|
||||
" background-color: #CECFC6;\n" +
|
||||
" font-family: monospace;\n" +
|
||||
" font-size: 10pt;\n" +
|
||||
" font-weight: 100;\n" +
|
||||
" width: 100%;\n" +
|
||||
" text-align: left;\n" +
|
||||
" margin: 0px 0px 0px 0px;\n" +
|
||||
" border: 0px;\n" +
|
||||
" padding: 5px;\n" +
|
||||
" border-width: 0px;\n" +
|
||||
" border-spacing: 0px;\n" +
|
||||
"}\n" +
|
||||
"table {\n" +
|
||||
" margin: 0px 0px 0px 0px;\n" +
|
||||
@ -495,14 +519,16 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
" font-family: monospace;\n" +
|
||||
" background-color: #ADAE9;\n" +
|
||||
"}\n" +
|
||||
".snarkAddInfo {\n" +
|
||||
" font-size: 10pt;\n" +
|
||||
"}\n" +
|
||||
".snarkConfigTitle {\n" +
|
||||
" font-size: 16pt;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
"}\n" +
|
||||
"</style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
"<p class=\"snarkTitle\">I2PSnark </p>\n";
|
||||
"<body>\n";
|
||||
|
||||
|
||||
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\">\n" +
|
||||
|
@ -1,4 +1,9 @@
|
||||
$Id: history.txt,v 1.356 2005/12/15 03:58:31 jrandom Exp $
|
||||
$Id: history.txt,v 1.357 2005/12/15 22:00:48 jrandom Exp $
|
||||
|
||||
2005-12-16 jrandom
|
||||
* Refuse torrents with too many files (128), avoiding ulimit errors.
|
||||
* Remove an fd leak in I2PSnark
|
||||
* Further I2PSnark web UI cleanup
|
||||
|
||||
2005-12-15 jrandom
|
||||
* Added a first pass to the I2PSnark web UI (see /i2psnark/)
|
||||
|
Reference in New Issue
Block a user