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);
|
private final Log _log = new Log(PeerCoordinator.class);
|
||||||
final MetaInfo metainfo;
|
final MetaInfo metainfo;
|
||||||
final Storage storage;
|
final Storage storage;
|
||||||
|
final Snark snark;
|
||||||
|
|
||||||
// package local for access by CheckDownLoadersTask
|
// package local for access by CheckDownLoadersTask
|
||||||
final static long CHECK_PERIOD = 20*1000; // 20 seconds
|
final static long CHECK_PERIOD = 20*1000; // 20 seconds
|
||||||
@ -70,12 +71,13 @@ public class PeerCoordinator implements PeerListener
|
|||||||
public int trackerSeenPeers = 0;
|
public int trackerSeenPeers = 0;
|
||||||
|
|
||||||
public PeerCoordinator(byte[] id, MetaInfo metainfo, Storage storage,
|
public PeerCoordinator(byte[] id, MetaInfo metainfo, Storage storage,
|
||||||
CoordinatorListener listener)
|
CoordinatorListener listener, Snark torrent)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.metainfo = metainfo;
|
this.metainfo = metainfo;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
this.snark = torrent;
|
||||||
|
|
||||||
// Make a list of pieces
|
// Make a list of pieces
|
||||||
wantedPieces = new ArrayList();
|
wantedPieces = new ArrayList();
|
||||||
@ -400,8 +402,9 @@ public class PeerCoordinator implements PeerListener
|
|||||||
}
|
}
|
||||||
catch (IOException ioe)
|
catch (IOException ioe)
|
||||||
{
|
{
|
||||||
Snark.fatal("Error reading storage", ioe);
|
snark.stopTorrent();
|
||||||
return null; // Never reached.
|
_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)
|
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);
|
wantedPieces.remove(p);
|
||||||
}
|
}
|
||||||
|
@ -346,12 +346,15 @@ public class Snark
|
|||||||
}
|
}
|
||||||
catch (IOException ioe)
|
catch (IOException ioe)
|
||||||
{
|
{
|
||||||
|
try { storage.close(); } catch (IOException ioee) {
|
||||||
|
ioee.printStackTrace();
|
||||||
|
}
|
||||||
fatal("Could not create storage", ioe);
|
fatal("Could not create storage", ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activity = "Collecting pieces";
|
activity = "Collecting pieces";
|
||||||
coordinator = new PeerCoordinator(id, meta, storage, clistener);
|
coordinator = new PeerCoordinator(id, meta, storage, clistener, this);
|
||||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||||
set.add(coordinator);
|
set.add(coordinator);
|
||||||
PeerAcceptor peeracceptor = new PeerAcceptor(set); //coordinator);
|
PeerAcceptor peeracceptor = new PeerAcceptor(set); //coordinator);
|
||||||
@ -374,7 +377,7 @@ public class Snark
|
|||||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||||
set.remove(coordinator);
|
set.remove(coordinator);
|
||||||
PeerCoordinator newCoord = new PeerCoordinator(coordinator.getID(), coordinator.getMetaInfo(),
|
PeerCoordinator newCoord = new PeerCoordinator(coordinator.getID(), coordinator.getMetaInfo(),
|
||||||
coordinator.getStorage(), coordinator.getListener());
|
coordinator.getStorage(), coordinator.getListener(), this);
|
||||||
set.add(newCoord);
|
set.add(newCoord);
|
||||||
coordinator = newCoord;
|
coordinator = newCoord;
|
||||||
coordinatorChanged = true;
|
coordinatorChanged = true;
|
||||||
@ -569,7 +572,7 @@ public class Snark
|
|||||||
/**
|
/**
|
||||||
* Aborts program abnormally.
|
* Aborts program abnormally.
|
||||||
*/
|
*/
|
||||||
public static void fatal(String s)
|
public void fatal(String s)
|
||||||
{
|
{
|
||||||
fatal(s, null);
|
fatal(s, null);
|
||||||
}
|
}
|
||||||
@ -577,12 +580,13 @@ public class Snark
|
|||||||
/**
|
/**
|
||||||
* Aborts program abnormally.
|
* Aborts program abnormally.
|
||||||
*/
|
*/
|
||||||
public static void fatal(String s, Throwable t)
|
public void fatal(String s, Throwable t)
|
||||||
{
|
{
|
||||||
I2PSnarkUtil.instance().debug(s, ERROR, t);
|
I2PSnarkUtil.instance().debug(s, ERROR, t);
|
||||||
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
|
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
|
||||||
//if (debug >= INFO && t != null)
|
//if (debug >= INFO && t != null)
|
||||||
// t.printStackTrace();
|
// t.printStackTrace();
|
||||||
|
stopTorrent();
|
||||||
throw new RuntimeException("die bart die");
|
throw new RuntimeException("die bart die");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
monitor.start();
|
monitor.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MAX_MESSAGES = 10;
|
private static final int MAX_MESSAGES = 5;
|
||||||
public void addMessage(String message) {
|
public void addMessage(String message) {
|
||||||
synchronized (_messages) {
|
synchronized (_messages) {
|
||||||
_messages.add(message);
|
_messages.add(message);
|
||||||
@ -243,6 +243,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
|
|
||||||
public Properties getConfig() { return _config; }
|
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 */
|
/** set of filenames that we are dealing with */
|
||||||
public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } }
|
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 Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } }
|
||||||
public void addTorrent(String 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);
|
File sfile = new File(filename);
|
||||||
try {
|
try {
|
||||||
filename = sfile.getCanonicalPath();
|
filename = sfile.getCanonicalPath();
|
||||||
@ -263,9 +274,31 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
synchronized (_snarks) {
|
synchronized (_snarks) {
|
||||||
torrent = (Snark)_snarks.get(filename);
|
torrent = (Snark)_snarks.get(filename);
|
||||||
if (torrent == null) {
|
if (torrent == null) {
|
||||||
torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath());
|
FileInputStream fis = null;
|
||||||
torrent.completeListener = this;
|
try {
|
||||||
_snarks.put(filename, torrent);
|
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 {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -330,6 +363,12 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
private class DirMonitor implements Runnable {
|
private class DirMonitor implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {}
|
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) {
|
while (true) {
|
||||||
File dir = getDataDir();
|
File dir = getDataDir();
|
||||||
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath());
|
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath());
|
||||||
|
@ -72,7 +72,8 @@ public class SnarkShutdown extends Thread
|
|||||||
}
|
}
|
||||||
catch(IOException ioe)
|
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++)
|
for (int i = 0; i < rafs.length; i++)
|
||||||
{
|
{
|
||||||
synchronized(rafs[i])
|
try {
|
||||||
{
|
synchronized(rafs[i])
|
||||||
rafs[i].close();
|
{
|
||||||
}
|
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);
|
throw new IOException("Error fetching " + s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
InputStream in = new FileInputStream(fetched);
|
in = new FileInputStream(fetched);
|
||||||
|
|
||||||
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
|
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
|
||||||
coordinator.getMetaInfo());
|
coordinator.getMetaInfo());
|
||||||
@ -270,6 +271,7 @@ public class TrackerClient extends Thread
|
|||||||
interval = info.getInterval() * 1000;
|
interval = info.getInterval() * 1000;
|
||||||
return info;
|
return info;
|
||||||
} finally {
|
} finally {
|
||||||
|
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||||
fetched.delete();
|
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
|
// 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("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + "\">\n");
|
||||||
out.write(HEADER);
|
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();
|
List msgs = _manager.getMessages();
|
||||||
for (int i = msgs.size()-1; i >= 0; i--) {
|
for (int i = msgs.size()-1; i >= 0; i--) {
|
||||||
String msg = (String)msgs.get(i);
|
String msg = (String)msgs.get(i);
|
||||||
out.write(msg + "\n");
|
out.write(msg + "\n");
|
||||||
}
|
}
|
||||||
out.write("</textarea>\n");
|
out.write("</pre></td></tr></table>\n");
|
||||||
|
|
||||||
out.write(TABLE_HEADER);
|
out.write(TABLE_HEADER);
|
||||||
|
|
||||||
@ -302,6 +306,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
|||||||
|
|
||||||
boolean isRunning = !snark.stopped;
|
boolean isRunning = !snark.stopped;
|
||||||
boolean isValid = snark.meta != null;
|
boolean isValid = snark.meta != null;
|
||||||
|
boolean singleFile = snark.meta.getFiles() == null;
|
||||||
|
|
||||||
String err = snark.coordinator.trackerProblems;
|
String err = snark.coordinator.trackerProblems;
|
||||||
int curPeers = snark.coordinator.getPeerCount();
|
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("<td valign=\"top\" align=\"left\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||||
out.write(statusString + "</td>\n\t");
|
out.write(statusString + "</td>\n\t");
|
||||||
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentName " + rowClass + "\">");
|
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 + "\">");
|
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB
|
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)
|
// 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("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("<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");
|
out.write("</form>\n</span>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,12 +480,22 @@ public class I2PSnarkServlet extends HttpServlet {
|
|||||||
" font-size: 16pt;\n" +
|
" font-size: 16pt;\n" +
|
||||||
" font-weight: bold;\n" +
|
" font-weight: bold;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
".snarkRefresh {\n" +
|
||||||
|
" font-size: 10pt;\n" +
|
||||||
|
"}\n" +
|
||||||
".snarkMessages {\n" +
|
".snarkMessages {\n" +
|
||||||
" border: none;\n" +
|
" border: none;\n" +
|
||||||
" background-color: #CECFC6;\n" +
|
" background-color: #CECFC6;\n" +
|
||||||
" font-family: monospace;\n" +
|
" font-family: monospace;\n" +
|
||||||
" font-size: 10pt;\n" +
|
" font-size: 10pt;\n" +
|
||||||
" font-weight: 100;\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" +
|
"}\n" +
|
||||||
"table {\n" +
|
"table {\n" +
|
||||||
" margin: 0px 0px 0px 0px;\n" +
|
" margin: 0px 0px 0px 0px;\n" +
|
||||||
@ -495,14 +519,16 @@ public class I2PSnarkServlet extends HttpServlet {
|
|||||||
" font-family: monospace;\n" +
|
" font-family: monospace;\n" +
|
||||||
" background-color: #ADAE9;\n" +
|
" background-color: #ADAE9;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
".snarkAddInfo {\n" +
|
||||||
|
" font-size: 10pt;\n" +
|
||||||
|
"}\n" +
|
||||||
".snarkConfigTitle {\n" +
|
".snarkConfigTitle {\n" +
|
||||||
" font-size: 16pt;\n" +
|
" font-size: 16pt;\n" +
|
||||||
" font-weight: bold;\n" +
|
" font-weight: bold;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"</style>\n" +
|
"</style>\n" +
|
||||||
"</head>\n" +
|
"</head>\n" +
|
||||||
"<body>\n" +
|
"<body>\n";
|
||||||
"<p class=\"snarkTitle\">I2PSnark </p>\n";
|
|
||||||
|
|
||||||
|
|
||||||
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\">\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
|
2005-12-15 jrandom
|
||||||
* Added a first pass to the I2PSnark web UI (see /i2psnark/)
|
* Added a first pass to the I2PSnark web UI (see /i2psnark/)
|
||||||
|
Reference in New Issue
Block a user