forked from I2P_Developers/i2p.i2p
Compare commits
59 Commits
i2p_0_6_1_
...
i2p_0_6_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da0837bd58 | ||
|
|
9094a62273 | ||
|
|
026183a655 | ||
|
|
b033c7945c | ||
|
|
0c2dcf0845 | ||
|
|
b6e597e5bf | ||
|
|
ae402baa71 | ||
|
|
d6c8a4d9eb | ||
|
|
8e2849b7e5 | ||
|
|
0aa0cd330f | ||
|
|
0960cafaf5 | ||
|
|
2088a28053 | ||
|
|
a5c4ba3bff | ||
|
|
1bbd2cf52e | ||
|
|
ce50efa60c | ||
|
|
a3c64a9ba3 | ||
|
|
1447164a8a | ||
|
|
bc0bf8d7ff | ||
|
|
9f346f488e | ||
|
|
760d7d9704 | ||
|
|
77310e17d1 | ||
|
|
e54b964929 | ||
|
|
809f3e847b | ||
|
|
f4beebe60d | ||
|
|
827e427f0b | ||
|
|
c02125511d | ||
|
|
1aa1069b6f | ||
|
|
91d281077d | ||
|
|
f339dec024 | ||
|
|
2aeef44f8d | ||
|
|
0fd41a9490 | ||
|
|
58f10d14b2 | ||
|
|
46ca42ddf8 | ||
|
|
e6e6d6f4ee | ||
|
|
8a87df605b | ||
|
|
8ca085bceb | ||
|
|
df47587db0 | ||
|
|
d705e0ad04 | ||
|
|
40d209dd7c | ||
|
|
7f2a0457bf | ||
|
|
f4749f2483 | ||
|
|
9c42830076 | ||
|
|
53ba6c2a64 | ||
|
|
61b3f21f69 | ||
|
|
506fd5f889 | ||
|
|
d538f888b4 | ||
|
|
976c5fdd47 | ||
|
|
b63f3437f2 | ||
|
|
e760f2e538 | ||
|
|
17c8fca779 | ||
|
|
87fda382c3 | ||
|
|
1e404cd7ac | ||
|
|
098f99d806 | ||
|
|
da93f96035 | ||
|
|
ead39cc87e | ||
|
|
e4e3c44459 | ||
|
|
af151e32e5 | ||
|
|
12819a2a17 | ||
|
|
87eedff254 |
@@ -33,6 +33,7 @@ public class I2PSnarkUtil {
|
||||
private I2PSocketManager _manager;
|
||||
private boolean _configured;
|
||||
private Set _shitlist;
|
||||
private int _maxUploaders;
|
||||
|
||||
private I2PSnarkUtil() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
@@ -42,6 +43,7 @@ public class I2PSnarkUtil {
|
||||
setI2CPConfig("127.0.0.1", 7654, null);
|
||||
_shitlist = new HashSet(64);
|
||||
_configured = false;
|
||||
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,12 +74,18 @@ public class I2PSnarkUtil {
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setMaxUploaders(int limit) {
|
||||
_maxUploaders = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public String getI2CPHost() { return _i2cpHost; }
|
||||
public int getI2CPPort() { return _i2cpPort; }
|
||||
public Map getI2CPOptions() { return _opts; }
|
||||
public String getEepProxyHost() { return _proxyHost; }
|
||||
public int getEepProxyPort() { return _proxyPort; }
|
||||
public boolean getEepProxySet() { return _shouldProxy; }
|
||||
public int getMaxUploaders() { return _maxUploaders; }
|
||||
|
||||
/**
|
||||
* Connect to the router, if we aren't already
|
||||
@@ -97,6 +105,10 @@ public class I2PSnarkUtil {
|
||||
opts.setProperty("i2p.streaming.inactivityTimeout", "90000");
|
||||
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
|
||||
opts.setProperty("i2p.streaming.inactivityAction", "2"); // 1 == disconnect, 2 == ping
|
||||
if (opts.getProperty("i2p.streaming.initialWindowSize") == null)
|
||||
opts.setProperty("i2p.streaming.initialWindowSize", "1");
|
||||
if (opts.getProperty("i2p.streaming.slowStartGrowthRateFactor") == null)
|
||||
opts.setProperty("i2p.streaming.slowStartGrowthRateFactor", "1");
|
||||
//if (opts.getProperty("i2p.streaming.writeTimeout") == null)
|
||||
// opts.setProperty("i2p.streaming.writeTimeout", "90000");
|
||||
//if (opts.getProperty("i2p.streaming.readTimeout") == null)
|
||||
|
||||
@@ -54,6 +54,10 @@ public class Peer implements Comparable
|
||||
private boolean deregister = true;
|
||||
private static long __id;
|
||||
private long _id;
|
||||
final static long CHECK_PERIOD = 40*1000; // 40 seconds
|
||||
final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long
|
||||
private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
|
||||
private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
|
||||
|
||||
/**
|
||||
* Creates a disconnected peer given a PeerID, your own id and the
|
||||
@@ -487,4 +491,82 @@ public class Peer implements Comparable
|
||||
s.retransmitRequests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return how much the peer has
|
||||
* Quite inefficient - a byte lookup table or counter in Bitfield would be much better
|
||||
*/
|
||||
public int completed()
|
||||
{
|
||||
PeerState s = state;
|
||||
if (s == null || s.bitfield == null)
|
||||
return 0;
|
||||
int count = 0;
|
||||
for (int i = 0; i < s.bitfield.size(); i++)
|
||||
if (s.bitfield.get(i))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if a peer is a seeder
|
||||
* Quite inefficient - a byte lookup table or counter in Bitfield would be much better
|
||||
*/
|
||||
public boolean isCompleted()
|
||||
{
|
||||
PeerState s = state;
|
||||
if (s == null || s.bitfield == null)
|
||||
return false;
|
||||
for (int i = 0; i < s.bitfield.size(); i++)
|
||||
if (!s.bitfield.get(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
*/
|
||||
public void setRateHistory(long up, long down)
|
||||
{
|
||||
setRate(up, uploaded_old);
|
||||
setRate(down, downloaded_old);
|
||||
}
|
||||
|
||||
private void setRate(long val, long array[])
|
||||
{
|
||||
synchronized(array) {
|
||||
for (int i = RATE_DEPTH-1; i > 0; i--)
|
||||
array[i] = array[i-1];
|
||||
array[0] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4-minute-average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return getRate(uploaded_old);
|
||||
}
|
||||
|
||||
public long getDownloadRate()
|
||||
{
|
||||
return getRate(downloaded_old);
|
||||
}
|
||||
|
||||
private long getRate(long array[])
|
||||
{
|
||||
long rate = 0;
|
||||
int i = 0;
|
||||
synchronized(array) {
|
||||
for ( ; i < RATE_DEPTH; i++){
|
||||
if (array[i] < 0)
|
||||
break;
|
||||
rate += array[i];
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
return 0;
|
||||
return rate / (i * CHECK_PERIOD / 1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,6 +41,17 @@ class PeerCheckerTask extends TimerTask
|
||||
{
|
||||
synchronized(coordinator.peers)
|
||||
{
|
||||
Iterator it = coordinator.peers.iterator();
|
||||
if ((!it.hasNext()) || coordinator.halted()) {
|
||||
coordinator.peerCount = 0;
|
||||
coordinator.interestedAndChoking = 0;
|
||||
coordinator.setRateHistory(0, 0);
|
||||
coordinator.uploaders = 0;
|
||||
if (coordinator.halted())
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate total uploading and worst downloader.
|
||||
long worstdownload = Long.MAX_VALUE;
|
||||
Peer worstDownloader = null;
|
||||
@@ -48,10 +59,7 @@ class PeerCheckerTask extends TimerTask
|
||||
int peers = 0;
|
||||
int uploaders = 0;
|
||||
int downloaders = 0;
|
||||
int interested = 0;
|
||||
int interesting = 0;
|
||||
int choking = 0;
|
||||
int choked = 0;
|
||||
int removedCount = 0;
|
||||
|
||||
long uploaded = 0;
|
||||
long downloaded = 0;
|
||||
@@ -59,8 +67,7 @@ class PeerCheckerTask extends TimerTask
|
||||
// Keep track of peers we remove now,
|
||||
// we will add them back to the end of the list.
|
||||
List removed = new ArrayList();
|
||||
|
||||
Iterator it = coordinator.peers.iterator();
|
||||
int uploadLimit = coordinator.allowedUploaders();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer peer = (Peer)it.next();
|
||||
@@ -80,19 +87,12 @@ class PeerCheckerTask extends TimerTask
|
||||
uploaders++;
|
||||
if (!peer.isChoked() && peer.isInteresting())
|
||||
downloaders++;
|
||||
if (peer.isInterested())
|
||||
interested++;
|
||||
if (peer.isInteresting())
|
||||
interesting++;
|
||||
if (peer.isChoking())
|
||||
choking++;
|
||||
if (peer.isChoked())
|
||||
choked++;
|
||||
|
||||
long upload = peer.getUploaded();
|
||||
uploaded += upload;
|
||||
long download = peer.getDownloaded();
|
||||
downloaded += download;
|
||||
peer.setRateHistory(upload, download);
|
||||
peer.resetCounters();
|
||||
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
@@ -110,8 +110,9 @@ class PeerCheckerTask extends TimerTask
|
||||
// If we are at our max uploaders and we have lots of other
|
||||
// interested peers try to make some room.
|
||||
// (Note use of coordinator.uploaders)
|
||||
if (coordinator.uploaders >= PeerCoordinator.MAX_UPLOADERS
|
||||
&& interested > PeerCoordinator.MAX_UPLOADERS
|
||||
if (((coordinator.uploaders == uploadLimit
|
||||
&& coordinator.interestedAndChoking > 0)
|
||||
|| coordinator.uploaders > uploadLimit)
|
||||
&& !peer.isChoking())
|
||||
{
|
||||
// Check if it still wants pieces from us.
|
||||
@@ -128,7 +129,7 @@ class PeerCheckerTask extends TimerTask
|
||||
it.remove();
|
||||
removed.add(peer);
|
||||
}
|
||||
else if (peer.isChoked())
|
||||
else if (peer.isInteresting() && peer.isChoked())
|
||||
{
|
||||
// If they are choking us make someone else a downloader
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
@@ -136,6 +137,21 @@ class PeerCheckerTask extends TimerTask
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
removedCount++;
|
||||
|
||||
// Put it at the back of the list
|
||||
it.remove();
|
||||
removed.add(peer);
|
||||
}
|
||||
else if (!peer.isInteresting() && !coordinator.completed())
|
||||
{
|
||||
// If they aren't interesting make someone else a downloader
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
Snark.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
removedCount++;
|
||||
|
||||
// Put it at the back of the list
|
||||
it.remove();
|
||||
@@ -152,17 +168,25 @@ class PeerCheckerTask extends TimerTask
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
removedCount++;
|
||||
|
||||
// Put it at the back of the list
|
||||
it.remove();
|
||||
removed.add(peer);
|
||||
}
|
||||
else if (!peer.isChoking() && download < worstdownload)
|
||||
else if (peer.isInteresting() && !peer.isChoked() &&
|
||||
download < worstdownload)
|
||||
{
|
||||
// Make sure download is good if we are uploading
|
||||
worstdownload = download;
|
||||
worstDownloader = peer;
|
||||
}
|
||||
else if (upload < worstdownload && coordinator.completed())
|
||||
{
|
||||
// Make sure upload is good if we are seeding
|
||||
worstdownload = upload;
|
||||
worstDownloader = peer;
|
||||
}
|
||||
}
|
||||
peer.retransmitRequests();
|
||||
peer.keepAlive();
|
||||
@@ -172,9 +196,10 @@ class PeerCheckerTask extends TimerTask
|
||||
// (can shift a bit by disconnecting peers)
|
||||
coordinator.uploaders = uploaders;
|
||||
|
||||
// Remove the worst downloader if needed.
|
||||
if (uploaders >= PeerCoordinator.MAX_UPLOADERS
|
||||
&& interested > PeerCoordinator.MAX_UPLOADERS
|
||||
// Remove the worst downloader if needed. (uploader if seeding)
|
||||
if (((uploaders == uploadLimit
|
||||
&& coordinator.interestedAndChoking > 0)
|
||||
|| uploaders > uploadLimit)
|
||||
&& worstDownloader != null)
|
||||
{
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
@@ -183,6 +208,7 @@ class PeerCheckerTask extends TimerTask
|
||||
|
||||
worstDownloader.setChoking(true);
|
||||
coordinator.uploaders--;
|
||||
removedCount++;
|
||||
|
||||
// Put it at the back of the list
|
||||
coordinator.peers.remove(worstDownloader);
|
||||
@@ -196,13 +222,11 @@ class PeerCheckerTask extends TimerTask
|
||||
// Put peers back at the end of the list that we removed earlier.
|
||||
coordinator.peers.addAll(removed);
|
||||
coordinator.peerCount = coordinator.peers.size();
|
||||
coordinator.interestedAndChoking += removedCount;
|
||||
|
||||
// store the rates
|
||||
coordinator.setRateHistory(uploaded, downloaded);
|
||||
|
||||
}
|
||||
if (coordinator.halted()) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class PeerConnectionIn implements Runnable
|
||||
private final DataInputStream din;
|
||||
|
||||
private Thread thread;
|
||||
private boolean quit;
|
||||
private volatile boolean quit;
|
||||
|
||||
public PeerConnectionIn(Peer peer, DataInputStream din)
|
||||
{
|
||||
@@ -51,6 +51,13 @@ class PeerConnectionIn implements Runnable
|
||||
Thread t = thread;
|
||||
if (t != null)
|
||||
t.interrupt();
|
||||
if (din != null) {
|
||||
try {
|
||||
din.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error closing the stream from " + peer, ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
|
||||
@@ -72,6 +72,16 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
Message m = null;
|
||||
PeerState state = null;
|
||||
boolean shouldFlush;
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
shouldFlush = !quit && peer.isConnected() && sendQueue.isEmpty();
|
||||
}
|
||||
if (shouldFlush)
|
||||
// Make sure everything will reach the other side.
|
||||
// flush while not holding lock, could take a long time
|
||||
dout.flush();
|
||||
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
while (!quit && peer.isConnected() && sendQueue.isEmpty())
|
||||
@@ -79,7 +89,8 @@ class PeerConnectionOut implements Runnable
|
||||
try
|
||||
{
|
||||
// Make sure everything will reach the other side.
|
||||
dout.flush();
|
||||
// don't flush while holding lock, could take a long time
|
||||
// dout.flush();
|
||||
|
||||
// Wait till more data arrives.
|
||||
sendQueue.wait(60*1000);
|
||||
@@ -197,10 +208,12 @@ class PeerConnectionOut implements Runnable
|
||||
/**
|
||||
* Adds a message to the sendQueue and notifies the method waiting
|
||||
* on the sendQueue to change.
|
||||
* If a PIECE message only, add a timeout.
|
||||
*/
|
||||
private void addMessage(Message m)
|
||||
{
|
||||
SimpleTimer.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT);
|
||||
if (m.type == Message.PIECE)
|
||||
SimpleTimer.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT);
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
sendQueue.add(m);
|
||||
@@ -387,7 +400,7 @@ class PeerConnectionOut implements Runnable
|
||||
m.begin = begin;
|
||||
m.length = length;
|
||||
m.data = bytes;
|
||||
m.off = begin;
|
||||
m.off = 0;
|
||||
m.len = length;
|
||||
addMessage(m);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class PeerCoordinator implements PeerListener
|
||||
// Approximation of the number of current uploaders.
|
||||
// Resynced by PeerChecker once in a while.
|
||||
int uploaders = 0;
|
||||
int interestedAndChoking = 0;
|
||||
|
||||
// final static int MAX_DOWNLOADERS = MAX_CONNECTIONS;
|
||||
// int downloaders = 0;
|
||||
@@ -104,6 +105,15 @@ public class PeerCoordinator implements PeerListener
|
||||
public Storage getStorage() { return storage; }
|
||||
public CoordinatorListener getListener() { return listener; }
|
||||
|
||||
// for web page detailed stats
|
||||
public List peerList()
|
||||
{
|
||||
synchronized(peers)
|
||||
{
|
||||
return new ArrayList(peers);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getID()
|
||||
{
|
||||
return id;
|
||||
@@ -132,7 +142,7 @@ public class PeerCoordinator implements PeerListener
|
||||
public long getLeft()
|
||||
{
|
||||
// XXX - Only an approximation.
|
||||
return storage.needed() * metainfo.getPieceLength(0);
|
||||
return ((long) storage.needed()) * metainfo.getPieceLength(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,12 +166,17 @@ public class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
public void setRateHistory(long up, long down)
|
||||
{
|
||||
for (int i = RATE_DEPTH-1; i > 0; i--){
|
||||
uploaded_old[i] = uploaded_old[i-1];
|
||||
downloaded_old[i] = downloaded_old[i-1];
|
||||
setRate(up, uploaded_old);
|
||||
setRate(down, downloaded_old);
|
||||
}
|
||||
|
||||
private static void setRate(long val, long array[])
|
||||
{
|
||||
synchronized(array) {
|
||||
for (int i = RATE_DEPTH-1; i > 0; i--)
|
||||
array[i] = array[i-1];
|
||||
array[0] = val;
|
||||
}
|
||||
uploaded_old[0] = up;
|
||||
downloaded_old[0] = down;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,21 +184,20 @@ public class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
public long getDownloadRate()
|
||||
{
|
||||
long rate = 0;
|
||||
for (int i = 0; i < RATE_DEPTH; i++){
|
||||
rate += downloaded_old[i];
|
||||
}
|
||||
return rate / (RATE_DEPTH * CHECK_PERIOD / 1000);
|
||||
return getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4-minute-average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return getRate(uploaded_old);
|
||||
}
|
||||
|
||||
private long getRate(long array[])
|
||||
{
|
||||
long rate = 0;
|
||||
for (int i = 0; i < RATE_DEPTH; i++){
|
||||
rate += uploaded_old[i];
|
||||
synchronized(array) {
|
||||
for (int i = 0; i < RATE_DEPTH; i++)
|
||||
rate += array[i];
|
||||
}
|
||||
return rate / (RATE_DEPTH * CHECK_PERIOD / 1000);
|
||||
}
|
||||
@@ -336,34 +350,41 @@ public class PeerCoordinator implements PeerListener
|
||||
// other peer that are interested, but are choking us.
|
||||
List interested = new LinkedList();
|
||||
synchronized (peers) {
|
||||
int count = 0;
|
||||
int unchokedCount = 0;
|
||||
int maxUploaders = allowedUploaders();
|
||||
Iterator it = peers.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer peer = (Peer)it.next();
|
||||
boolean remove = false;
|
||||
if (uploaders < MAX_UPLOADERS
|
||||
&& peer.isChoking()
|
||||
&& peer.isInterested())
|
||||
if (peer.isChoking() && peer.isInterested())
|
||||
{
|
||||
if (!peer.isChoked())
|
||||
interested.add(0, peer);
|
||||
else
|
||||
interested.add(peer);
|
||||
count++;
|
||||
if (uploaders < maxUploaders)
|
||||
{
|
||||
if (!peer.isChoked())
|
||||
interested.add(unchokedCount++, peer);
|
||||
else
|
||||
interested.add(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (uploaders < MAX_UPLOADERS && interested.size() > 0)
|
||||
while (uploaders < maxUploaders && interested.size() > 0)
|
||||
{
|
||||
Peer peer = (Peer)interested.remove(0);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Unchoke: " + peer);
|
||||
peer.setChoking(false);
|
||||
uploaders++;
|
||||
count--;
|
||||
// Put peer back at the end of the list.
|
||||
peers.remove(peer);
|
||||
peers.add(peer);
|
||||
peerCount = peers.size();
|
||||
}
|
||||
interestedAndChoking = count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,14 +500,14 @@ public class PeerCoordinator implements PeerListener
|
||||
* Returns a byte array containing the requested piece or null of
|
||||
* the piece is unknown.
|
||||
*/
|
||||
public byte[] gotRequest(Peer peer, int piece)
|
||||
public byte[] gotRequest(Peer peer, int piece, int off, int len)
|
||||
{
|
||||
if (halted)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return storage.getPiece(piece);
|
||||
return storage.getPiece(piece, off, len);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
@@ -566,14 +587,27 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
|
||||
// Announce to the world we have it!
|
||||
// Disconnect from other seeders when we get the last piece
|
||||
synchronized(peers)
|
||||
{
|
||||
List toDisconnect = new ArrayList();
|
||||
Iterator it = peers.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer p = (Peer)it.next();
|
||||
if (p.isConnected())
|
||||
p.have(piece);
|
||||
{
|
||||
if (completed() && p.isCompleted())
|
||||
toDisconnect.add(p);
|
||||
else
|
||||
p.have(piece);
|
||||
}
|
||||
}
|
||||
it = toDisconnect.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer p = (Peer)it.next();
|
||||
p.disconnect(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,7 +629,7 @@ public class PeerCoordinator implements PeerListener
|
||||
{
|
||||
synchronized(peers)
|
||||
{
|
||||
if (uploaders < MAX_UPLOADERS)
|
||||
if (uploaders < allowedUploaders())
|
||||
{
|
||||
if(peer.isChoking())
|
||||
{
|
||||
@@ -763,5 +797,20 @@ public class PeerCoordinator implements PeerListener
|
||||
for (int i = 0; arr[i] >= 0; i++)
|
||||
markUnrequestedIfOnlyOne(peer, arr[i]);
|
||||
}
|
||||
|
||||
/** Return number of allowed uploaders for this torrent.
|
||||
** Check with Snark to see if we are over the total upload limit.
|
||||
*/
|
||||
public int allowedUploaders()
|
||||
{
|
||||
if (Snark.overUploadLimit(uploaders)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Over limit, uploaders was: " + uploaders);
|
||||
return uploaders - 1;
|
||||
} else if (uploaders < MAX_UPLOADERS)
|
||||
return uploaders + 1;
|
||||
else
|
||||
return MAX_UPLOADERS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,11 +107,13 @@ public interface PeerListener
|
||||
*
|
||||
* @param peer the Peer that wants the piece.
|
||||
* @param piece the piece number requested.
|
||||
* @param off byte offset into the piece.
|
||||
* @param len length of the chunk requested.
|
||||
*
|
||||
* @return a byte array containing the piece or null when the piece
|
||||
* is not available (which is a protocol error).
|
||||
*/
|
||||
byte[] gotRequest(Peer peer, int piece);
|
||||
byte[] gotRequest(Peer peer, int piece, int off, int len);
|
||||
|
||||
/**
|
||||
* Called when a (partial) piece has been downloaded from the peer.
|
||||
@@ -167,5 +169,4 @@ public interface PeerListener
|
||||
* @param peer the peer that is disconnecting
|
||||
*/
|
||||
void markUnrequested(Peer peer);
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ class PeerState
|
||||
private boolean resend = false;
|
||||
|
||||
private final static int MAX_PIPELINE = 2;
|
||||
private final static int PARTSIZE = 64*1024; // default was 16K, i2p-bt uses 64KB
|
||||
private final static int PARTSIZE = 32*1024; // Snark was 16K, i2p-bt uses 64KB
|
||||
private final static int MAX_PARTSIZE = 64*1024; // Don't let anybody request more than this
|
||||
|
||||
PeerState(Peer peer, PeerListener listener, MetaInfo metainfo,
|
||||
PeerConnectionIn in, PeerConnectionOut out)
|
||||
@@ -173,7 +174,7 @@ class PeerState
|
||||
|| begin < 0
|
||||
|| begin > metainfo.getPieceLength(piece)
|
||||
|| length <= 0
|
||||
|| length > 4*PARTSIZE)
|
||||
|| length > MAX_PARTSIZE)
|
||||
{
|
||||
// XXX - Protocol error -> disconnect?
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -184,7 +185,7 @@ class PeerState
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] pieceBytes = listener.gotRequest(peer, piece);
|
||||
byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length);
|
||||
if (pieceBytes == null)
|
||||
{
|
||||
// XXX - Protocol error-> diconnect?
|
||||
@@ -194,7 +195,7 @@ class PeerState
|
||||
}
|
||||
|
||||
// More sanity checks
|
||||
if (begin >= pieceBytes.length || begin + length > pieceBytes.length)
|
||||
if (length != pieceBytes.length)
|
||||
{
|
||||
// XXX - Protocol error-> disconnect?
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -537,7 +538,14 @@ class PeerState
|
||||
&& (lastRequest == null || lastRequest.piece != nextPiece))
|
||||
{
|
||||
int piece_length = metainfo.getPieceLength(nextPiece);
|
||||
byte[] bs = new byte[piece_length];
|
||||
//Catch a common place for OOMs esp. on 1MB pieces
|
||||
byte[] bs;
|
||||
try {
|
||||
bs = new byte[piece_length];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_log.warn("Out of memory, can't request piece " + nextPiece, oom);
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = Math.min(piece_length, PARTSIZE);
|
||||
Request req = new Request(nextPiece, bs, 0, length);
|
||||
|
||||
@@ -234,6 +234,7 @@ public class Snark
|
||||
public String rootDataDir = ".";
|
||||
public CompleteListener completeListener;
|
||||
public boolean stopped;
|
||||
byte[] id;
|
||||
|
||||
Snark(String torrent, String ip, int user_port,
|
||||
StorageListener slistener, CoordinatorListener clistener) {
|
||||
@@ -268,7 +269,7 @@ public class Snark
|
||||
// zeros bytes, then three bytes filled with snark and then
|
||||
// sixteen random bytes.
|
||||
byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
|
||||
byte[] id = new byte[20];
|
||||
id = new byte[20];
|
||||
Random random = new Random();
|
||||
int i;
|
||||
for (i = 0; i < 9; i++)
|
||||
@@ -283,6 +284,11 @@ public class Snark
|
||||
|
||||
int port;
|
||||
IOException lastException = null;
|
||||
/*
|
||||
* Don't start a tunnel if the torrent isn't going to be started.
|
||||
* If we are starting,
|
||||
* startTorrent() will force a connect.
|
||||
*
|
||||
boolean ok = I2PSnarkUtil.instance().connect();
|
||||
if (!ok) fatal("Unable to connect to I2P");
|
||||
I2PServerSocket serversocket = I2PSnarkUtil.instance().getServerSocket();
|
||||
@@ -292,6 +298,7 @@ public class Snark
|
||||
Destination d = serversocket.getManager().getSession().getMyDestination();
|
||||
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
|
||||
}
|
||||
*/
|
||||
|
||||
// Figure out what the torrent argument represents.
|
||||
meta = null;
|
||||
@@ -361,6 +368,9 @@ public class Snark
|
||||
activity = "Checking storage";
|
||||
storage = new Storage(meta, slistener);
|
||||
storage.check(rootDataDir);
|
||||
// have to figure out when to reopen
|
||||
// if (!start)
|
||||
// storage.close();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
@@ -371,14 +381,19 @@ public class Snark
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* see comment above
|
||||
*
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(id, meta, storage, clistener, this);
|
||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||
set.add(coordinator);
|
||||
ConnectionAcceptor acceptor = ConnectionAcceptor.instance();
|
||||
acceptor.startAccepting(set, serversocket);
|
||||
|
||||
trackerclient = new TrackerClient(meta, coordinator);
|
||||
*/
|
||||
|
||||
if (start)
|
||||
startTorrent();
|
||||
}
|
||||
@@ -386,6 +401,26 @@ public class Snark
|
||||
* Start up contacting peers and querying the tracker
|
||||
*/
|
||||
public void startTorrent() {
|
||||
boolean ok = I2PSnarkUtil.instance().connect();
|
||||
if (!ok) fatal("Unable to connect to I2P");
|
||||
if (coordinator == null) {
|
||||
I2PServerSocket serversocket = I2PSnarkUtil.instance().getServerSocket();
|
||||
if (serversocket == null)
|
||||
fatal("Unable to listen for I2P connections");
|
||||
else {
|
||||
Destination d = serversocket.getManager().getSession().getMyDestination();
|
||||
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
|
||||
}
|
||||
debug("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient", NOTICE);
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(id, meta, storage, this, this);
|
||||
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
|
||||
set.add(coordinator);
|
||||
ConnectionAcceptor acceptor = ConnectionAcceptor.instance();
|
||||
acceptor.startAccepting(set, serversocket);
|
||||
trackerclient = new TrackerClient(meta, coordinator);
|
||||
}
|
||||
|
||||
stopped = false;
|
||||
boolean coordinatorChanged = false;
|
||||
if (coordinator.halted()) {
|
||||
@@ -402,6 +437,17 @@ public class Snark
|
||||
if (!trackerclient.started() && !coordinatorChanged) {
|
||||
trackerclient.start();
|
||||
} else if (trackerclient.halted() || coordinatorChanged) {
|
||||
try
|
||||
{
|
||||
storage.reopen(rootDataDir);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
try { storage.close(); } catch (IOException ioee) {
|
||||
ioee.printStackTrace();
|
||||
}
|
||||
fatal("Could not reopen storage", ioe);
|
||||
}
|
||||
TrackerClient newClient = new TrackerClient(coordinator.getMetaInfo(), coordinator);
|
||||
if (!trackerclient.halted())
|
||||
trackerclient.halt();
|
||||
@@ -708,4 +754,23 @@ public class Snark
|
||||
public interface CompleteListener {
|
||||
public void torrentComplete(Snark snark);
|
||||
}
|
||||
|
||||
/** Maintain a configurable total uploader cap
|
||||
*/
|
||||
final static int MIN_TOTAL_UPLOADERS = 4;
|
||||
final static int MAX_TOTAL_UPLOADERS = 10;
|
||||
public static boolean overUploadLimit(int uploaders) {
|
||||
PeerCoordinatorSet coordinators = PeerCoordinatorSet.instance();
|
||||
if (coordinators == null || uploaders <= 0)
|
||||
return false;
|
||||
int totalUploaders = 0;
|
||||
for (Iterator iter = coordinators.iterator(); iter.hasNext(); ) {
|
||||
PeerCoordinator c = (PeerCoordinator)iter.next();
|
||||
if (!c.halted())
|
||||
totalUploaders += c.uploaders;
|
||||
}
|
||||
int limit = I2PSnarkUtil.instance().getMaxUploaders();
|
||||
Snark.debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
|
||||
return totalUploaders > limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
/** map of (canonical) filename to Snark instance (unsynchronized) */
|
||||
private Map _snarks;
|
||||
private Object _addSnarkLock;
|
||||
private String _configFile;
|
||||
private Properties _config;
|
||||
private I2PAppContext _context;
|
||||
@@ -27,6 +28,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions";
|
||||
public static final String PROP_EEP_HOST = "i2psnark.eepHost";
|
||||
public static final String PROP_EEP_PORT = "i2psnark.eepPort";
|
||||
public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total";
|
||||
public static final String PROP_DIR = "i2psnark.dir";
|
||||
|
||||
public static final String PROP_AUTO_START = "i2snark.autoStart";
|
||||
@@ -34,12 +36,13 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
private SnarkManager() {
|
||||
_snarks = new HashMap();
|
||||
_addSnarkLock = new Object();
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(SnarkManager.class);
|
||||
_messages = new ArrayList(16);
|
||||
loadConfig("i2psnark.config");
|
||||
int minutes = getStartupDelayMinutes();
|
||||
_messages.add("Starting up torrents in " + minutes + (minutes == 1 ? " minute" : " minutes"));
|
||||
_messages.add("Adding torrents in " + minutes + (minutes == 1 ? " minute" : " minutes"));
|
||||
I2PThread monitor = new I2PThread(new DirMonitor(), "Snark DirMonitor");
|
||||
monitor.setDaemon(true);
|
||||
monitor.start();
|
||||
@@ -97,6 +100,8 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
_config.setProperty(PROP_EEP_HOST, "localhost");
|
||||
if (!_config.containsKey(PROP_EEP_PORT))
|
||||
_config.setProperty(PROP_EEP_PORT, "4444");
|
||||
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
|
||||
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
|
||||
if (!_config.containsKey(PROP_DIR))
|
||||
_config.setProperty(PROP_DIR, "i2psnark");
|
||||
if (!_config.containsKey(PROP_AUTO_START))
|
||||
@@ -127,6 +132,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
int eepPort = getInt(PROP_EEP_PORT, 4444);
|
||||
if (eepHost != null)
|
||||
I2PSnarkUtil.instance().setProxy(eepHost, eepPort);
|
||||
I2PSnarkUtil.instance().setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
|
||||
getDataDir().mkdirs();
|
||||
}
|
||||
|
||||
@@ -142,7 +148,8 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
}
|
||||
|
||||
public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts) {
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit) {
|
||||
boolean changed = false;
|
||||
if (eepHost != null) {
|
||||
int port = I2PSnarkUtil.instance().getEepProxyPort();
|
||||
@@ -157,6 +164,20 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
addMessage("EepProxy location changed to " + eepHost + ":" + port);
|
||||
}
|
||||
}
|
||||
if (upLimit != null) {
|
||||
int limit = I2PSnarkUtil.instance().getMaxUploaders();
|
||||
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
|
||||
if ( limit != I2PSnarkUtil.instance().getEepProxyPort()) {
|
||||
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
|
||||
I2PSnarkUtil.instance().setMaxUploaders(limit);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit);
|
||||
addMessage("Total uploaders limit changed to " + limit);
|
||||
} else {
|
||||
addMessage("Minimum total uploaders limit is " + Snark.MIN_TOTAL_UPLOADERS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i2cpHost != null) {
|
||||
int oldI2CPPort = I2PSnarkUtil.instance().getI2CPPort();
|
||||
String oldI2CPHost = I2PSnarkUtil.instance().getI2CPHost();
|
||||
@@ -269,7 +290,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } }
|
||||
public void addTorrent(String filename) { addTorrent(filename, false); }
|
||||
public void addTorrent(String filename, boolean dontAutoStart) {
|
||||
if (!I2PSnarkUtil.instance().connected()) {
|
||||
if ((!dontAutoStart) && !I2PSnarkUtil.instance().connected()) {
|
||||
addMessage("Connecting to I2P");
|
||||
boolean ok = I2PSnarkUtil.instance().connect();
|
||||
if (!ok) {
|
||||
@@ -289,7 +310,16 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
Snark torrent = null;
|
||||
synchronized (_snarks) {
|
||||
torrent = (Snark)_snarks.get(filename);
|
||||
if (torrent == null) {
|
||||
}
|
||||
// don't hold the _snarks lock while verifying the torrent
|
||||
if (torrent == null) {
|
||||
synchronized (_addSnarkLock) {
|
||||
// double-check
|
||||
synchronized (_snarks) {
|
||||
if(_snarks.get(filename) != null)
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(sfile);
|
||||
@@ -305,7 +335,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
} else {
|
||||
torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath());
|
||||
torrent.completeListener = this;
|
||||
_snarks.put(filename, torrent);
|
||||
synchronized (_snarks) {
|
||||
_snarks.put(filename, torrent);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage());
|
||||
@@ -315,9 +347,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// ok, snark created, now lets start it up or configure it further
|
||||
File f = new File(filename);
|
||||
@@ -446,10 +478,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
if (existingNames.contains(foundNames.get(i))) {
|
||||
// already known. noop
|
||||
} else {
|
||||
if (I2PSnarkUtil.instance().connect())
|
||||
addTorrent((String)foundNames.get(i));
|
||||
else
|
||||
if (shouldAutoStart() && !I2PSnarkUtil.instance().connect())
|
||||
addMessage("Unable to connect to I2P");
|
||||
addTorrent((String)foundNames.get(i), !shouldAutoStart());
|
||||
}
|
||||
}
|
||||
// now lets see which ones have been removed...
|
||||
@@ -466,6 +497,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
private static final String DEFAULT_TRACKERS[] = {
|
||||
"Postman's tracker", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php"
|
||||
, "eBook Tracker", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php"
|
||||
, "Gaytorrents Tracker", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php"
|
||||
, "NickyB Tracker", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php"
|
||||
, "Orion's tracker", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php"
|
||||
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
|
||||
};
|
||||
|
||||
@@ -76,7 +76,6 @@ public class Storage
|
||||
throws IOException
|
||||
{
|
||||
this.listener = listener;
|
||||
|
||||
// Create names, rafs and lengths arrays.
|
||||
getFiles(baseFile);
|
||||
|
||||
@@ -132,13 +131,14 @@ public class Storage
|
||||
// Creates piece hases for a new storage.
|
||||
public void create() throws IOException
|
||||
{
|
||||
if (true) {
|
||||
// if (true) {
|
||||
fast_digestCreate();
|
||||
} else {
|
||||
orig_digestCreate();
|
||||
}
|
||||
// } else {
|
||||
// orig_digestCreate();
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
private void orig_digestCreate() throws IOException {
|
||||
// Calculate piece_hashes
|
||||
MessageDigest digest = null;
|
||||
@@ -156,7 +156,7 @@ public class Storage
|
||||
byte[] piece = new byte[piece_size];
|
||||
for (int i = 0; i < pieces; i++)
|
||||
{
|
||||
int length = getUncheckedPiece(i, piece, 0);
|
||||
int length = getUncheckedPiece(i, piece);
|
||||
digest.update(piece, 0, length);
|
||||
byte[] hash = digest.digest();
|
||||
for (int j = 0; j < 20; j++)
|
||||
@@ -174,6 +174,7 @@ public class Storage
|
||||
// Reannounce to force recalculating the info_hash.
|
||||
metainfo = metainfo.reannounce(metainfo.getAnnounce());
|
||||
}
|
||||
*/
|
||||
|
||||
private void fast_digestCreate() throws IOException {
|
||||
// Calculate piece_hashes
|
||||
@@ -184,7 +185,7 @@ public class Storage
|
||||
byte[] piece = new byte[piece_size];
|
||||
for (int i = 0; i < pieces; i++)
|
||||
{
|
||||
int length = getUncheckedPiece(i, piece, 0);
|
||||
int length = getUncheckedPiece(i, piece);
|
||||
digest.update(piece, 0, length);
|
||||
byte[] hash = digest.digest();
|
||||
for (int j = 0; j < 20; j++)
|
||||
@@ -219,6 +220,8 @@ public class Storage
|
||||
{
|
||||
File f = (File)it.next();
|
||||
names[i] = f.getPath();
|
||||
if (base.isDirectory() && names[i].startsWith(base.getPath()))
|
||||
names[i] = names[i].substring(base.getPath().length() + 1);
|
||||
lengths[i] = f.length();
|
||||
rafs[i] = new RandomAccessFile(f, "r");
|
||||
i++;
|
||||
@@ -335,6 +338,49 @@ public class Storage
|
||||
checkCreateFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reopen the file descriptors for a restart
|
||||
* Do existence check but no length check or data reverification
|
||||
*/
|
||||
public void reopen(String rootDir) throws IOException
|
||||
{
|
||||
File base = new File(rootDir, filterName(metainfo.getName()));
|
||||
|
||||
List files = metainfo.getFiles();
|
||||
if (files == null)
|
||||
{
|
||||
// Reopen base as file.
|
||||
Snark.debug("Reopening file: " + base, Snark.NOTICE);
|
||||
if (!base.exists())
|
||||
throw new IOException("Could not reopen file " + base);
|
||||
|
||||
if (!base.canWrite()) // hope we can get away with this, if we are only seeding...
|
||||
rafs[0] = new RandomAccessFile(base, "r");
|
||||
else
|
||||
rafs[0] = new RandomAccessFile(base, "rw");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reopen base as dir.
|
||||
Snark.debug("Reopening directory: " + base, Snark.NOTICE);
|
||||
if (!base.isDirectory())
|
||||
throw new IOException("Could not reopen directory " + base);
|
||||
|
||||
int size = files.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
File f = getFileFromNames(base, (List)files.get(i));
|
||||
if (!f.exists())
|
||||
throw new IOException("Could not reopen file " + f);
|
||||
if (!f.canWrite()) // see above re: only seeding
|
||||
rafs[i] = new RandomAccessFile(f, "r");
|
||||
else
|
||||
rafs[i] = new RandomAccessFile(f, "rw");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes 'suspicious' characters from the give file name.
|
||||
*/
|
||||
@@ -370,6 +416,17 @@ public class Storage
|
||||
return f;
|
||||
}
|
||||
|
||||
private File getFileFromNames(File base, List names) throws IOException
|
||||
{
|
||||
Iterator it = names.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
String name = filterName((String)it.next());
|
||||
base = new File(base, name);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
private void checkCreateFiles() throws IOException
|
||||
{
|
||||
// Whether we are resuming or not,
|
||||
@@ -400,7 +457,7 @@ public class Storage
|
||||
byte[] piece = new byte[metainfo.getPieceLength(0)];
|
||||
for (int i = 0; i < pieces; i++)
|
||||
{
|
||||
int length = getUncheckedPiece(i, piece, 0);
|
||||
int length = getUncheckedPiece(i, piece);
|
||||
boolean correctHash = metainfo.checkPiece(i, piece, 0, length);
|
||||
if (correctHash)
|
||||
{
|
||||
@@ -463,16 +520,23 @@ public class Storage
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing the requested piece or null if
|
||||
* Returns a byte array containing a portion of the requested piece or null if
|
||||
* the storage doesn't contain the piece yet.
|
||||
*/
|
||||
public byte[] getPiece(int piece) throws IOException
|
||||
public byte[] getPiece(int piece, int off, int len) throws IOException
|
||||
{
|
||||
if (!bitfield.get(piece))
|
||||
return null;
|
||||
|
||||
byte[] bs = new byte[metainfo.getPieceLength(piece)];
|
||||
getUncheckedPiece(piece, bs, 0);
|
||||
//Catch a common place for OOMs esp. on 1MB pieces
|
||||
byte[] bs;
|
||||
try {
|
||||
bs = new byte[len];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
I2PSnarkUtil.instance().debug("Out of memory, can't honor request for piece " + piece, Snark.WARNING, oom);
|
||||
return null;
|
||||
}
|
||||
getUncheckedPiece(piece, bs, off, len);
|
||||
return bs;
|
||||
}
|
||||
|
||||
@@ -565,15 +629,20 @@ public class Storage
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getUncheckedPiece(int piece, byte[] bs, int off)
|
||||
private int getUncheckedPiece(int piece, byte[] bs)
|
||||
throws IOException
|
||||
{
|
||||
return getUncheckedPiece(piece, bs, 0, metainfo.getPieceLength(piece));
|
||||
}
|
||||
|
||||
private int getUncheckedPiece(int piece, byte[] bs, int off, int length)
|
||||
throws IOException
|
||||
{
|
||||
// XXX - copy/paste code from putPiece().
|
||||
|
||||
// Early typecast, avoid possibly overflowing a temp integer
|
||||
long start = (long) piece * (long) metainfo.getPieceLength(0);
|
||||
long start = ((long) piece * (long) metainfo.getPieceLength(0)) + off;
|
||||
|
||||
int length = metainfo.getPieceLength(piece);
|
||||
int i = 0;
|
||||
long raflen = lengths[i];
|
||||
while (start > raflen)
|
||||
@@ -591,7 +660,7 @@ public class Storage
|
||||
synchronized(rafs[i])
|
||||
{
|
||||
rafs[i].seek(start);
|
||||
rafs[i].readFully(bs, off + read, len);
|
||||
rafs[i].readFully(bs, read, len);
|
||||
}
|
||||
read += len;
|
||||
if (need - len > 0)
|
||||
|
||||
@@ -153,7 +153,10 @@ public class TrackerClient extends I2PThread
|
||||
coordinator.trackerProblems = ioe.getMessage();
|
||||
}
|
||||
|
||||
if (!started && !stop)
|
||||
if (stop)
|
||||
break;
|
||||
|
||||
if (!started)
|
||||
{
|
||||
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||
try
|
||||
|
||||
@@ -49,17 +49,34 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
if ( (nonce != null) && (nonce.equals(String.valueOf(_nonce))) )
|
||||
processRequest(req);
|
||||
|
||||
String peerParam = req.getParameter("p");
|
||||
String peerString;
|
||||
if (peerParam == null) {
|
||||
peerString = "";
|
||||
} else {
|
||||
peerString = "?p=" + peerParam;
|
||||
}
|
||||
|
||||
PrintWriter out = resp.getWriter();
|
||||
out.write(HEADER_BEGIN);
|
||||
// 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() + peerString + "\">\n");
|
||||
out.write(HEADER);
|
||||
|
||||
out.write("<table border=\"0\" width=\"100%\">\n");
|
||||
out.write("<tr><td width=\"5%\" class=\"snarkTitle\" valign=\"top\" align=\"left\">");
|
||||
out.write("<tr><td width=\"20%\" 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>");
|
||||
out.write("<table border=\"0\" width=\"100%\">\n");
|
||||
out.write("<tr><td><a href=\"" + req.getRequestURI() + peerString + "\" class=\"snarkRefresh\">Refresh</a><br />\n");
|
||||
out.write("<td><a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\">Forum</a><br />\n");
|
||||
out.write("<tr><td><a href=\"http://de-ebook-archiv.i2p/pub/bt/\" class=\"snarkRefresh\">eBook</a><br />\n");
|
||||
out.write("<td><a href=\"http://gaytorrents.i2p/\" class=\"snarkRefresh\">GayTorrents</a><br />\n");
|
||||
out.write("<tr><td><a href=\"http://nickyb.i2p/bittorrent/\" class=\"snarkRefresh\">NickyB</a><br />\n");
|
||||
out.write("<td><a href=\"http://orion.i2p/bt/\" class=\"snarkRefresh\">Orion</a><br />\n");
|
||||
out.write("<tr><td><a href=\"http://tracker.postman.i2p/\" class=\"snarkRefresh\">Postman</a><br />\n");
|
||||
out.write("<td> \n");
|
||||
out.write("</table>\n");
|
||||
out.write("</td><td width=\"80%\" 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);
|
||||
@@ -67,13 +84,27 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
}
|
||||
out.write("</pre></td></tr></table>\n");
|
||||
|
||||
out.write(TABLE_HEADER);
|
||||
|
||||
List snarks = getSortedSnarks(req);
|
||||
String uri = req.getRequestURI();
|
||||
out.write(TABLE_HEADER);
|
||||
if (I2PSnarkUtil.instance().connected() && snarks.size() > 0) {
|
||||
if (peerParam != null)
|
||||
out.write("(<a href=\"" + req.getRequestURI() + "\">Hide Peers</a>)<br />\n");
|
||||
else
|
||||
out.write("(<a href=\"" + req.getRequestURI() + "?p=1" + "\">Show Peers</a>)<br />\n");
|
||||
}
|
||||
out.write(TABLE_HEADER2);
|
||||
out.write("<th align=\"left\" valign=\"top\">");
|
||||
if (I2PSnarkUtil.instance().connected())
|
||||
out.write("<a href=\"" + uri + "?action=StopAll&nonce=" + _nonce +
|
||||
"\" title=\"Stop all torrents and the i2p tunnel\">Stop All</a>");
|
||||
else
|
||||
out.write(" ");
|
||||
out.write("</th></tr></thead>\n");
|
||||
for (int i = 0; i < snarks.size(); i++) {
|
||||
Snark snark = (Snark)snarks.get(i);
|
||||
displaySnark(out, snark, uri, i, stats);
|
||||
boolean showPeers = "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
|
||||
displaySnark(out, snark, uri, i, stats, showPeers);
|
||||
}
|
||||
if (snarks.size() <= 0) {
|
||||
out.write(TABLE_EMPTY);
|
||||
@@ -88,6 +119,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
out.write(TABLE_FOOTER);
|
||||
|
||||
writeAddForm(out, req);
|
||||
if (true) // seeding needs to register the torrent first, so we can't start it automatically (boo, hiss)
|
||||
writeSeedForm(out, req);
|
||||
@@ -239,7 +271,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String i2cpHost = req.getParameter("i2cpHost");
|
||||
String i2cpPort = req.getParameter("i2cpPort");
|
||||
String i2cpOpts = req.getParameter("i2cpOpts");
|
||||
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts);
|
||||
String upLimit = req.getParameter("upLimit");
|
||||
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit);
|
||||
} else if ("Create torrent".equals(action)) {
|
||||
String baseData = req.getParameter("baseFile");
|
||||
if (baseData != null) {
|
||||
@@ -249,7 +282,9 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
if ( (announceURLOther != null) && (announceURLOther.trim().length() > "http://.i2p/announce".length()) )
|
||||
announceURL = announceURLOther;
|
||||
|
||||
if (baseFile.exists() && baseFile.isFile()) {
|
||||
if (announceURL == null || announceURL.length() <= 0)
|
||||
_manager.addMessage("Error creating torrent - you must select a tracker");
|
||||
else if (baseFile.exists()) {
|
||||
try {
|
||||
Storage s = new Storage(baseFile, announceURL, null);
|
||||
s.create();
|
||||
@@ -267,12 +302,22 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
} catch (IOException ioe) {
|
||||
_manager.addMessage("Error creating a torrent for " + baseFile.getAbsolutePath() + ": " + ioe.getMessage());
|
||||
}
|
||||
} else if (baseFile.exists()) {
|
||||
_manager.addMessage("I2PSnark doesn't yet support creating multifile torrents");
|
||||
} else {
|
||||
_manager.addMessage("Cannot create a torrent for the nonexistant data: " + baseFile.getAbsolutePath());
|
||||
_manager.addMessage("Cannot create a torrent for the nonexistent data: " + baseFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
} else if ("StopAll".equals(action)) {
|
||||
_manager.addMessage("Stopping all torrents and closing the I2P tunnel");
|
||||
List snarks = getSortedSnarks(req);
|
||||
for (int i = 0; i < snarks.size(); i++) {
|
||||
Snark snark = (Snark)snarks.get(i);
|
||||
if (!snark.stopped)
|
||||
_manager.stopTorrent(snark.torrent, false);
|
||||
}
|
||||
if (I2PSnarkUtil.instance().connected()) {
|
||||
I2PSnarkUtil.instance().disconnect();
|
||||
_manager.addMessage("I2P tunnel closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +336,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
|
||||
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60;
|
||||
private static final int MAX_DISPLAYED_ERROR_LENGTH = 30;
|
||||
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[]) throws IOException {
|
||||
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers) throws IOException {
|
||||
String filename = snark.torrent;
|
||||
File f = new File(filename);
|
||||
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
|
||||
@@ -305,16 +350,23 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
long remaining = (long) snark.storage.needed() * (long) snark.meta.getPieceLength(0);
|
||||
if (remaining > total)
|
||||
remaining = total;
|
||||
long downBps = snark.coordinator.getDownloadRate();
|
||||
long upBps = snark.coordinator.getUploadRate();
|
||||
long downBps = 0;
|
||||
long upBps = 0;
|
||||
if (snark.coordinator != null) {
|
||||
downBps = snark.coordinator.getDownloadRate();
|
||||
upBps = snark.coordinator.getUploadRate();
|
||||
}
|
||||
long remainingSeconds;
|
||||
if (downBps > 0)
|
||||
remainingSeconds = remaining / downBps;
|
||||
else
|
||||
remainingSeconds = -1;
|
||||
long uploaded = snark.coordinator.getUploaded();
|
||||
boolean isRunning = !snark.stopped;
|
||||
stats[0] += snark.coordinator.getDownloaded();
|
||||
long uploaded = 0;
|
||||
if (snark.coordinator != null) {
|
||||
uploaded = snark.coordinator.getUploaded();
|
||||
stats[0] += snark.coordinator.getDownloaded();
|
||||
}
|
||||
stats[1] += uploaded;
|
||||
if (isRunning) {
|
||||
stats[2] += downBps;
|
||||
@@ -324,13 +376,22 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
boolean isValid = snark.meta != null;
|
||||
boolean singleFile = snark.meta.getFiles() == null;
|
||||
|
||||
String err = snark.coordinator.trackerProblems;
|
||||
int curPeers = snark.coordinator.getPeerCount();
|
||||
int knownPeers = snark.coordinator.trackerSeenPeers;
|
||||
String err = null;
|
||||
int curPeers = 0;
|
||||
int knownPeers = 0;
|
||||
if (snark.coordinator != null) {
|
||||
err = snark.coordinator.trackerProblems;
|
||||
curPeers = snark.coordinator.getPeerCount();
|
||||
knownPeers = snark.coordinator.trackerSeenPeers;
|
||||
}
|
||||
|
||||
String statusString = "Unknown";
|
||||
if (err != null) {
|
||||
if (isRunning)
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "TrackerErr (" +
|
||||
curPeers + "/" + knownPeers +
|
||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
|
||||
else if (isRunning)
|
||||
statusString = "TrackerErr (" + curPeers + "/" + knownPeers + " peers)";
|
||||
else {
|
||||
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
||||
@@ -338,13 +399,25 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
statusString = "TrackerErr (" + err + ")";
|
||||
}
|
||||
} else if (remaining <= 0) {
|
||||
if (isRunning)
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "Seeding (" +
|
||||
curPeers + "/" + knownPeers +
|
||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
|
||||
else if (isRunning)
|
||||
statusString = "Seeding (" + curPeers + "/" + knownPeers + " peers)";
|
||||
else
|
||||
statusString = "Complete";
|
||||
} else {
|
||||
if (isRunning && curPeers > 0 && downBps > 0)
|
||||
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
|
||||
statusString = "OK (" +
|
||||
curPeers + "/" + knownPeers +
|
||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
|
||||
else if (isRunning && curPeers > 0 && downBps > 0)
|
||||
statusString = "OK (" + curPeers + "/" + knownPeers + " peers)";
|
||||
else if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "Stalled (" +
|
||||
curPeers + "/" + knownPeers +
|
||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
|
||||
else if (isRunning && curPeers > 0)
|
||||
statusString = "Stalled (" + curPeers + "/" + knownPeers + " peers)";
|
||||
else if (isRunning)
|
||||
@@ -388,23 +461,84 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write(formatSize(upBps) + "ps");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentAction " + rowClass + "\">");
|
||||
String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash());
|
||||
if (showPeers)
|
||||
parameters = parameters + "&p=1";
|
||||
if (isRunning) {
|
||||
out.write("<a href=\"" + uri + "?action=Stop&nonce=" + _nonce
|
||||
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
|
||||
out.write("<a href=\"" + uri + "?action=Stop" + parameters
|
||||
+ "\" title=\"Stop the torrent\">Stop</a>");
|
||||
} else {
|
||||
if (isValid)
|
||||
out.write("<a href=\"" + uri + "?action=Start&nonce=" + _nonce
|
||||
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
|
||||
out.write("<a href=\"" + uri + "?action=Start" + parameters
|
||||
+ "\" title=\"Start the torrent\">Start</a> ");
|
||||
out.write("<a href=\"" + uri + "?action=Remove&nonce=" + _nonce
|
||||
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
|
||||
out.write("<a href=\"" + uri + "?action=Remove" + parameters
|
||||
+ "\" title=\"Remove the torrent from the active list, deleting the .torrent file\">Remove</a><br />");
|
||||
out.write("<a href=\"" + uri + "?action=Delete&nonce=" + _nonce
|
||||
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
|
||||
out.write("<a href=\"" + uri + "?action=Delete" + parameters
|
||||
+ "\" title=\"Delete the .torrent file and the associated data file(s)\">Delete</a> ");
|
||||
}
|
||||
out.write("</td>\n</tr>\n");
|
||||
if(showPeers && isRunning && curPeers > 0) {
|
||||
List peers = snark.coordinator.peerList();
|
||||
Iterator it = peers.iterator();
|
||||
while (it.hasNext()) {
|
||||
Peer peer = (Peer)it.next();
|
||||
if (!peer.isConnected())
|
||||
continue;
|
||||
out.write("<tr class=\"" + rowClass + "\">");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
String ch = peer.toString().substring(0, 4);
|
||||
String client;
|
||||
if ("AwMD".equals(ch))
|
||||
client = "I2PSnark";
|
||||
else if ("BFJT".equals(ch))
|
||||
client = "I2PRufus";
|
||||
else if ("TTMt".equals(ch))
|
||||
client = "I2P-BT";
|
||||
else if ("LUFa".equals(ch))
|
||||
client = "Azureus";
|
||||
else
|
||||
client = "Unknown";
|
||||
out.write("<font size=-1>" + client + "</font> <tt>" + peer.toString().substring(5, 9) + "</tt>");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
float pct = (float) (100.0 * (float) peer.completed() / snark.meta.getPieces());
|
||||
if (pct == 100.0)
|
||||
out.write("<font size=-1>Seed</font>");
|
||||
else {
|
||||
String ps = String.valueOf(pct);
|
||||
if (ps.length() > 5)
|
||||
ps = ps.substring(0, 5);
|
||||
out.write("<font size=-1>" + ps + "%</font>");
|
||||
}
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
if (remaining > 0) {
|
||||
if (peer.isInteresting() && !peer.isChoked())
|
||||
out.write("<font color=#008000>");
|
||||
else
|
||||
out.write("<font color=#a00000>");
|
||||
out.write("<font size=-1>" + formatSize(peer.getDownloadRate()) + "ps</font></font>");
|
||||
}
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
if (pct != 100.0) {
|
||||
if (peer.isInterested() && !peer.isChoking())
|
||||
out.write("<font color=#008000>");
|
||||
else
|
||||
out.write("<font color=#a00000>");
|
||||
out.write("<font size=-1>" + formatSize(peer.getUploadRate()) + "ps</font></font>");
|
||||
}
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td></tr>\n\t");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException {
|
||||
@@ -418,7 +552,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
|
||||
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
|
||||
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" />\n");
|
||||
out.write("From URL : <input type=\"text\" name=\"newURL\" size=\"50\" value=\"" + newURL + "\" /> \n");
|
||||
out.write("<span class=\"snarkConfigTitle\">Add Torrent:</span><br />\n");
|
||||
out.write("From URL : <input type=\"text\" name=\"newURL\" size=\"80\" value=\"" + newURL + "\" /> \n");
|
||||
// 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");
|
||||
@@ -433,10 +568,11 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
if (baseFile == null)
|
||||
baseFile = "";
|
||||
|
||||
out.write("<span class=\"snarkNewTorrent\">\n");
|
||||
out.write("<span class=\"snarkNewTorrent\"><hr />\n");
|
||||
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
|
||||
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
|
||||
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" />\n");
|
||||
out.write("<span class=\"snarkConfigTitle\">Create Torrent:</span><br />\n");
|
||||
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br />\n");
|
||||
out.write("Data to seed: " + _manager.getDataDir().getAbsolutePath() + File.separatorChar
|
||||
+ "<input type=\"text\" name=\"baseFile\" size=\"20\" value=\"" + baseFile
|
||||
@@ -472,7 +608,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String uri = req.getRequestURI();
|
||||
String dataDir = _manager.getDataDir().getAbsolutePath();
|
||||
boolean autoStart = _manager.shouldAutoStart();
|
||||
int seedPct = 0;
|
||||
//int seedPct = 0;
|
||||
|
||||
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
|
||||
out.write("<span class=\"snarkConfig\"><hr />\n");
|
||||
@@ -486,6 +622,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
//Auto add: <input type="checkbox" name="autoAdd" value="true" title="If true, automatically add torrents that are found in the data directory" />
|
||||
//Auto stop: <input type="checkbox" name="autoStop" value="true" title="If true, automatically stop torrents that are removed from the data directory" />
|
||||
//out.write("<br />\n");
|
||||
/*
|
||||
out.write("Seed percentage: <select name=\"seedPct\" disabled=\"true\" >\n\t");
|
||||
if (seedPct <= 0)
|
||||
out.write("<option value=\"0\" selected=\"true\">Unlimited</option>\n\t");
|
||||
@@ -500,6 +637,9 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
else
|
||||
out.write("<option value=\"150\">150%</option>\n\t");
|
||||
out.write("</select><br />\n");
|
||||
*/
|
||||
out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\""
|
||||
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" /> peers<br />\n");
|
||||
|
||||
//out.write("<hr />\n");
|
||||
out.write("EepProxy host: <input type=\"text\" name=\"eepHost\" value=\""
|
||||
@@ -517,22 +657,23 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String val = (String)options.get(key);
|
||||
opts.append(key).append('=').append(val).append(' ');
|
||||
}
|
||||
out.write("I2CP opts: <input type=\"text\" name=\"i2cpOpts\" size=\"40\" value=\""
|
||||
out.write("I2CP opts: <input type=\"text\" name=\"i2cpOpts\" size=\"80\" value=\""
|
||||
+ opts.toString() + "\" /><br />\n");
|
||||
out.write("<input type=\"submit\" value=\"Save configuration\" name=\"action\" />\n");
|
||||
out.write("</span>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
// rounding makes us look faster :)
|
||||
private String formatSize(long bytes) {
|
||||
if (bytes < 5*1024)
|
||||
return bytes + "B";
|
||||
else if (bytes < 5*1024*1024)
|
||||
return (bytes/1024) + "KB";
|
||||
return ((bytes + 512)/1024) + "KB";
|
||||
else if (bytes < 5*1024*1024*1024l)
|
||||
return (bytes/(1024*1024)) + "MB";
|
||||
return ((bytes + 512*1024)/(1024*1024)) + "MB";
|
||||
else
|
||||
return (bytes/(1024*1024*1024)) + "GB";
|
||||
return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "GB";
|
||||
}
|
||||
|
||||
private static final String HEADER_BEGIN = "<html>\n" +
|
||||
@@ -590,8 +731,6 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
"}\n" +
|
||||
".snarkNewTorrent {\n" +
|
||||
" font-size: 10pt;\n" +
|
||||
" font-family: monospace;\n" +
|
||||
" background-color: #ADAE9;\n" +
|
||||
"}\n" +
|
||||
".snarkAddInfo {\n" +
|
||||
" font-size: 10pt;\n" +
|
||||
@@ -610,15 +749,15 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
|
||||
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" cellpadding=\"0 10px\">\n" +
|
||||
"<thead>\n" +
|
||||
"<tr><th align=\"left\" valign=\"top\">Status</th>\n" +
|
||||
"<tr><th align=\"left\" valign=\"top\">Status \n";
|
||||
|
||||
private static final String TABLE_HEADER2 = "</th>\n" +
|
||||
" <th align=\"left\" valign=\"top\">Torrent</th>\n" +
|
||||
" <th align=\"right\" valign=\"top\">ETA</th>\n" +
|
||||
" <th align=\"right\" valign=\"top\">Downloaded</th>\n" +
|
||||
" <th align=\"right\" valign=\"top\">Uploaded</th>\n" +
|
||||
" <th align=\"right\" valign=\"top\">Down Rate</th>\n" +
|
||||
" <th align=\"right\" valign=\"top\">Up Rate</th>\n" +
|
||||
" <th> </th></tr>\n" +
|
||||
"</thead>\n";
|
||||
" <th align=\"right\" valign=\"top\">Up Rate</th>\n";
|
||||
|
||||
private static final String TABLE_TOTAL = "<tfoot>\n" +
|
||||
"<tr><th align=\"left\" valign=\"top\">Totals</th>\n" +
|
||||
|
||||
@@ -112,6 +112,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"or naming one of them differently.<P/>")
|
||||
.getBytes();
|
||||
|
||||
private final static byte[] ERR_BAD_PROTOCOL =
|
||||
("HTTP/1.1 403 Bad Protocol\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
"<html><body><H1>I2P ERROR: NON-HTTP PROTOCOL</H1>"+
|
||||
"The request uses a bad protocol. "+
|
||||
"The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed.<BR>")
|
||||
.getBytes();
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
@@ -483,7 +493,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
if (method == null || destination == null) {
|
||||
l.log("No HTTP method found in the request.");
|
||||
if (out != null) {
|
||||
out.write(ERR_REQUEST_DENIED);
|
||||
if ("http://".equalsIgnoreCase(protocol))
|
||||
out.write(ERR_REQUEST_DENIED);
|
||||
else
|
||||
out.write(ERR_BAD_PROTOCOL);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
|
||||
@@ -282,6 +282,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
"PART",
|
||||
"WALLOPS",
|
||||
"ERROR",
|
||||
"KICK",
|
||||
"H", // "hide operator status" (after kicking an op)
|
||||
"TOPIC"
|
||||
};
|
||||
|
||||
|
||||
@@ -3,29 +3,30 @@
|
||||
|
||||
<target name="all" depends="build" />
|
||||
<target name="fetchJettylib" >
|
||||
<available property="jetty.available" file="jetty-5.1.6.zip" />
|
||||
<available property="jetty.available" file="jetty-5.1.12.zip" />
|
||||
<ant target="doFetchJettylib" />
|
||||
</target>
|
||||
<target name="doFetchJettylib" unless="jetty.available" >
|
||||
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.6" />
|
||||
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.12" />
|
||||
<echo message="distribution (http://jetty.mortbay.org/). These are not " />
|
||||
<echo message="necessary for using I2P, but are used by some applications on top of I2P," />
|
||||
<echo message="such as the routerconsole." />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.6.zip" verbose="true" dest="jetty-5.1.6.zip" />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.12.zip" verbose="true" dest="jetty-5.1.12.zip" />
|
||||
<ant target="doExtract" />
|
||||
</target>
|
||||
<target name="doExtract">
|
||||
<unzip src="jetty-5.1.6.zip" dest="." />
|
||||
<unzip src="jetty-5.1.12.zip" dest="." />
|
||||
<mkdir dir="jettylib" />
|
||||
<copy todir="jettylib">
|
||||
<fileset dir="jetty-5.1.6/lib">
|
||||
<fileset dir="jetty-5.1.12/lib">
|
||||
<include name="*.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="jettylib">
|
||||
<fileset dir="jetty-5.1.6/ext">
|
||||
<fileset dir="jetty-5.1.12/ext">
|
||||
<include name="ant.jar" />
|
||||
<include name="commons-el.jar" />
|
||||
<include name="commons-logging.jar" />
|
||||
<include name="jasper-compiler.jar" />
|
||||
<include name="jasper-runtime.jar" />
|
||||
<include name="javax.servlet.jar" />
|
||||
@@ -33,9 +34,7 @@
|
||||
<include name="xercesImpl.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<!-- note the rename, to keep compat with old rev, since we only used the API anyway -->
|
||||
<copy file="jetty-5.1.6/ext/commons-logging-api.jar" tofile="jettylib/commons-logging.jar" />
|
||||
<delete dir="jetty-5.1.6" />
|
||||
<delete dir="jetty-5.1.12" />
|
||||
</target>
|
||||
<target name="build" depends="fetchJettylib" />
|
||||
<target name="builddep" />
|
||||
|
||||
@@ -53,9 +53,7 @@ public class ConfigNetHandler extends FormHandler {
|
||||
private boolean _ratesOnly;
|
||||
|
||||
protected void processForm() {
|
||||
if (_reseedRequested) {
|
||||
reseed();
|
||||
} else if (_saveRequested || ( (_action != null) && ("Save changes".equals(_action)) )) {
|
||||
if (_saveRequested || ( (_action != null) && ("Save changes".equals(_action)) )) {
|
||||
saveChanges();
|
||||
} else if (_recheckReachabilityRequested) {
|
||||
recheckReachability();
|
||||
@@ -64,7 +62,6 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void setReseed(String moo) { _reseedRequested = true; }
|
||||
public void setSave(String moo) { _saveRequested = true; }
|
||||
public void setEnabletimesync(String moo) { _timeSyncEnabled = true; }
|
||||
public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; }
|
||||
@@ -107,95 +104,9 @@ public class ConfigNetHandler extends FormHandler {
|
||||
public void setOutboundburstfactor(String factor) {
|
||||
_outboundBurst = (factor != null ? factor.trim() : null);
|
||||
}
|
||||
public void setReseedfrom(String url) {
|
||||
_reseedFrom = (url != null ? url.trim() : null);
|
||||
}
|
||||
public void setSharePercentage(String pct) {
|
||||
_sharePct = (pct != null ? pct.trim() : null);
|
||||
}
|
||||
|
||||
|
||||
private static final String DEFAULT_SEED_URL = ReseedHandler.DEFAULT_SEED_URL;
|
||||
/**
|
||||
* Reseed has been requested, so lets go ahead and do it. Fetch all of
|
||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||
* save them into this router's netDb dir.
|
||||
*
|
||||
*/
|
||||
private void reseed() {
|
||||
String seedURL = DEFAULT_SEED_URL;
|
||||
if (_reseedFrom != null)
|
||||
seedURL = _reseedFrom;
|
||||
try {
|
||||
URL dir = new URL(seedURL);
|
||||
String content = new String(readURL(dir));
|
||||
Set urls = new HashSet();
|
||||
int cur = 0;
|
||||
while (true) {
|
||||
int start = content.indexOf("href=\"routerInfo-", cur);
|
||||
if (start < 0)
|
||||
break;
|
||||
|
||||
int end = content.indexOf(".dat\">", start);
|
||||
String name = content.substring(start+"href=\"routerInfo-".length(), end);
|
||||
urls.add(name);
|
||||
cur = end + 1;
|
||||
}
|
||||
|
||||
int fetched = 0;
|
||||
int errors = 0;
|
||||
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
|
||||
try {
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
addFormNotice("Reseeded with " + fetched + " peers (and " + errors + " failures)");
|
||||
} catch (Throwable t) {
|
||||
_context.logManager().getLog(ConfigNetHandler.class).error("Error reseeding", t);
|
||||
addFormError("Error reseeding (RESEED_EXCEPTION)");
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchSeed(String seedURL, String peer) throws Exception {
|
||||
URL url = new URL(seedURL + (seedURL.endsWith("/") ? "" : "/") + "routerInfo-" + peer + ".dat");
|
||||
|
||||
byte data[] = readURL(url);
|
||||
writeSeed(peer, data);
|
||||
}
|
||||
|
||||
private byte[] readURL(URL url) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||
URLConnection con = url.openConnection();
|
||||
InputStream in = con.getInputStream();
|
||||
byte buf[] = new byte[1024];
|
||||
while (true) {
|
||||
int read = in.read(buf);
|
||||
if (read < 0)
|
||||
break;
|
||||
baos.write(buf, 0, read);
|
||||
}
|
||||
in.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private void writeSeed(String name, byte data[]) throws Exception {
|
||||
// props taken from KademliaNetworkDatabaseFacade...
|
||||
String dirName = _context.getProperty("router.networkDatabase.dbDir", "netDb");
|
||||
File netDbDir = new File(dirName);
|
||||
if (!netDbDir.exists()) {
|
||||
boolean ok = netDbDir.mkdirs();
|
||||
if (ok)
|
||||
addFormNotice("Network database directory created: " + dirName);
|
||||
else
|
||||
addFormNotice("Error creating network database directory: " + dirName);
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
|
||||
fos.write(data);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private void recheckReachability() {
|
||||
_context.commSystem().recheckReachability();
|
||||
|
||||
@@ -22,6 +22,7 @@ import net.i2p.util.I2PThread;
|
||||
*
|
||||
*/
|
||||
public class ReseedHandler {
|
||||
|
||||
private static ReseedRunner _reseedRunner = new ReseedRunner();
|
||||
|
||||
public void setReseedNonce(String nonce) {
|
||||
@@ -66,7 +67,7 @@ public class ReseedHandler {
|
||||
*
|
||||
*/
|
||||
private static void reseed(boolean echoStatus) {
|
||||
String seedURL = System.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
String seedURL = I2PAppContext.getGlobalContext().getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
if ( (seedURL == null) || (seedURL.trim().length() <= 0) )
|
||||
seedURL = DEFAULT_SEED_URL;
|
||||
try {
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<p><b>Note: changing this setting will terminate all of your connections and effectively
|
||||
restart your router.</b>
|
||||
<hr />
|
||||
<!--
|
||||
<b>Dynamic Router Keys: </b>
|
||||
<input type="checkbox" name="dynamicKeys" value="true" <jsp:getProperty name="nethelper" property="dynamicKeysChecked" /> /><br />
|
||||
<p>
|
||||
@@ -97,6 +98,7 @@
|
||||
though such would likely already be the case anyway, since the IP address changed.
|
||||
</p>
|
||||
<hr />
|
||||
-->
|
||||
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@ public class Connection {
|
||||
private long _lifetimeDupMessageSent;
|
||||
private long _lifetimeDupMessageReceived;
|
||||
|
||||
public static final long MAX_RESEND_DELAY = 10*1000;
|
||||
public static final long MAX_RESEND_DELAY = 45*1000;
|
||||
public static final long MIN_RESEND_DELAY = 2*1000;
|
||||
|
||||
/** wait up to 5 minutes after disconnection so we can ack/close packets */
|
||||
@@ -247,6 +247,7 @@ public class Connection {
|
||||
}
|
||||
long now = _context.clock().now();
|
||||
if (_resetSentOn + 10*1000 > now) return; // don't send resets too fast
|
||||
if (_resetReceived) return;
|
||||
_resetSent = true;
|
||||
if (_resetSentOn <= 0)
|
||||
_resetSentOn = now;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
static final int INITIAL_WINDOW_SIZE = 12;
|
||||
static final int DEFAULT_MAX_SENDS = 8;
|
||||
|
||||
static final int MIN_WINDOW_SIZE = INITIAL_WINDOW_SIZE;
|
||||
static final int MIN_WINDOW_SIZE = 1;
|
||||
|
||||
public ConnectionOptions() {
|
||||
super();
|
||||
@@ -205,8 +205,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
public int getRTT() { return _rtt; }
|
||||
public void setRTT(int ms) {
|
||||
if (_rto == 0) {
|
||||
_rttDev = ms;
|
||||
_rto = (int)Connection.MAX_RESEND_DELAY;
|
||||
_rttDev = ms / 2;
|
||||
_rto = ms + ms / 2;
|
||||
}
|
||||
synchronized (_trend) {
|
||||
_trend[0] = _trend[1];
|
||||
|
||||
@@ -28,10 +28,13 @@ public class UpdaterServlet extends GenericServlet {
|
||||
super.init(config);
|
||||
} catch (ServletException exp) {
|
||||
}
|
||||
/*
|
||||
UpdaterThread thread = new UpdaterThread();
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
System.out.println("INFO: Starting Syndie Updater " + Updater.VERSION);
|
||||
*/
|
||||
System.out.println("INFO: Syndie Updater DISABLED. Use the new Syndie from http://syndie.i2p.net/");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,11 @@
|
||||
<a href="blogs.jsp">blogs</a></p>
|
||||
<p><a href="post.jsp">Create</a> a new post of your own</p>
|
||||
<p><a href="about.html">Learn more</a> about Syndie</p>
|
||||
<p><b>NOTE:</b> This version of Syndie is being replaced by
|
||||
<a href="http://syndie.i2p.net">the new Syndie</a>!
|
||||
The new Syndie is a standalone application under active development.
|
||||
Please give the new Syndie a try, as it has lots more traffic
|
||||
than this version. Don't expect anybody to see your posts here.</p>
|
||||
</td></tr></table>
|
||||
</div>
|
||||
</body></html>
|
||||
|
||||
14
build.xml
14
build.xml
@@ -7,6 +7,7 @@
|
||||
<echo message=" installer: build the GUI installer" />
|
||||
<echo message=" tarball: tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" />
|
||||
<echo message=" updater: tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" />
|
||||
<echo message=" updaterWithJetty: tar the built i2p specific files and jetty into an i2pupdate.zip (extracts safely over existing installs)" />
|
||||
<echo message=" distclean: clean up all derived files" />
|
||||
<echo message=" syndie: generate a standalone syndie install" />
|
||||
<echo message=" i2psnark: generate a standalone i2psnark install" />
|
||||
@@ -292,6 +293,9 @@
|
||||
<target name="updater" depends="prepupdate">
|
||||
<zip destfile="i2pupdate.zip" basedir="pkg-temp" />
|
||||
</target>
|
||||
<target name="updaterWithJetty" depends="prepjupdate">
|
||||
<zip destfile="i2pupdate.zip" basedir="pkg-temp" />
|
||||
</target>
|
||||
<target name="updateTest" depends="prepupdate">
|
||||
<ant dir="core/java/" target="jarTest" />
|
||||
<copy file="core/java/build/i2ptest.jar" todir="pkg-temp/lib" />
|
||||
@@ -353,6 +357,16 @@
|
||||
<copy file="installer/resources/blogMeta.snm" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/meta.snm" />
|
||||
<copy file="installer/resources/blogPost.snd" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1132012800001.snd" />
|
||||
</target>
|
||||
<target name="prepjupdate" depends="prepupdate, buildWEB">
|
||||
<copy file="build/ant.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/xercesImpl.jar" todir="pkg-temp/lib/" />
|
||||
</target>
|
||||
<target name="installer" depends="preppkg">
|
||||
<taskdef name="izpack" classpath="${basedir}/installer/lib/izpack/standalone-compiler.jar" classname="com.izforge.izpack.ant.IzPackTask" />
|
||||
<jar destfile="./pkg-temp/lib/copy.jar" basedir="./core/java/build/obj" includes="net/i2p/util/*.class">
|
||||
|
||||
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.8 $ $Date: 2006-09-09 12:46:25 $";
|
||||
public final static String VERSION = "0.6.1.26";
|
||||
public final static String ID = "$Revision: 1.70 $ $Date: 2007-02-15 18:25:05 $";
|
||||
public final static String VERSION = "0.6.1.28";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Timestamper implements Runnable {
|
||||
private boolean _initialized;
|
||||
|
||||
private static final int DEFAULT_QUERY_FREQUENCY = 5*60*1000;
|
||||
private static final String DEFAULT_SERVER_LIST = "pool.ntp.org, pool.ntp.org, pool.ntp.org";
|
||||
private static final String DEFAULT_SERVER_LIST = "0.pool.ntp.org, 1.pool.ntp.org, 2.pool.ntp.org";
|
||||
private static final boolean DEFAULT_DISABLED = true;
|
||||
/** how many times do we have to query if we are changing the clock? */
|
||||
private static final int DEFAULT_CONCURRING_SERVERS = 3;
|
||||
|
||||
148
history.txt
148
history.txt
@@ -1,7 +1,153 @@
|
||||
$Id: history.txt,v 1.531 2006-10-08 17:52:59 complication Exp $
|
||||
$Id: history.txt,v 1.561 2007-03-17 16:18:12 jrandom Exp $
|
||||
|
||||
* 2007-03-17 0.6.1.28 released
|
||||
|
||||
2007-03-13 zzz
|
||||
* i2psnark: Make max total uploaders configurable (thanks Amiga4000!)
|
||||
|
||||
2007-03-12 jrandom
|
||||
* dodge a race on startup (thanks zzz!)
|
||||
|
||||
2007-03-10 zzz
|
||||
* Streaming lib: Change initial RTT deviation from RTT to RTT/2
|
||||
(RFC 2988) to reduce early RTO values
|
||||
|
||||
2007-03-08 zzz
|
||||
* i2psnark changes to improve upload performance:
|
||||
* Implement total uploader limit (10)
|
||||
* Don't timeout non-piece messages out
|
||||
* Change chunk size to 32K (was 64K)
|
||||
* Change request limit to 64K (was 256K)
|
||||
* i2psnark: Disconnect from seeds when complete
|
||||
|
||||
2007-03-07 zzz
|
||||
* Remove dynamic router keys from config.jsp
|
||||
|
||||
2007-03-07 zzz
|
||||
* Streaming lib changes to improve upstream performance during congestion:
|
||||
* Change min window size from 12 to 1
|
||||
* Change max timeout from 10 to 45 sec
|
||||
* Change initial timeout from 10 to 15 sec
|
||||
* Change intial window size for i2psnark from 12 to 1
|
||||
* Change slow start growth rate for i2psnark from 1/2 to 1
|
||||
|
||||
2007-03-04 zzz
|
||||
* Update eepsite_index.html
|
||||
|
||||
2007-03-03 zzz
|
||||
* Upgrade from Jetty 5.1.6 to 5.1.12 which fixes spaces in URL
|
||||
* Add a updaterWithJetty build target
|
||||
|
||||
2007-03-03 zzz
|
||||
* Implement priority sending for NTCP
|
||||
* Disable trimForOverload() in tunnel BuildExecutor which
|
||||
was preventing tunnel builds when outbound traffic was high
|
||||
(i.e. most of the time when running i2psnark)
|
||||
|
||||
2007-02-28 zzz
|
||||
* i2psnark: File reopen cleanup
|
||||
|
||||
2007-02-28 zzz
|
||||
* i2psnark: Add peer details to web page
|
||||
|
||||
* 2007-02-15 0.6.1.27 released
|
||||
|
||||
2007-02-15 jrandom
|
||||
* Limit the whispering floodfill sends to at most 3 randomly
|
||||
chosen from the known floodfill peers
|
||||
|
||||
2007-02-14 jrandom
|
||||
* Don't filter out KICK and H(ide oper status) IRC messages
|
||||
(thanks Takk and postman!)
|
||||
|
||||
2007-02-13 jrandom
|
||||
* Tell our peers about who we know in the floodfill netDb every
|
||||
6 hours or so, mitigating the situation where peers lose track
|
||||
of floodfill routers.
|
||||
* Disable the Syndie updater (people should use the new Syndie,
|
||||
not this one)
|
||||
* Disable the eepsite tunnel by default
|
||||
|
||||
2007-01-30 zzz
|
||||
* i2psnark: Don't hold _snarks lock while checking a snark,
|
||||
so web page is responsive at startup
|
||||
|
||||
2007-01-29 zzz
|
||||
* i2psnark: Add NickyB tracker
|
||||
|
||||
2007-01-28 zzz
|
||||
* i2psnark: Don't hold sendQueue lock while flushing output,
|
||||
to make everything run smoother
|
||||
|
||||
2007-01-27 zzz
|
||||
* i2psnark: Fix orphaned Snark reader tasks leading to OOMs
|
||||
|
||||
2007-01-20 Complication
|
||||
* Drop overlooked comment
|
||||
|
||||
2007-01-20 Complication
|
||||
* Modify ReseedHandler to query the "i2p.reseedURL" property from I2PAppContext
|
||||
instead of System, so setting a reseed URL in advanced configuration has effect.
|
||||
* Clean out obsolete reseed code from ConfigNetHandler.
|
||||
|
||||
2007-01-20 zzz
|
||||
* i2psnark: More choking rotation tweaks
|
||||
* Improve performance by not reading in the whole
|
||||
piece from disk for each request. A huge memory savings
|
||||
on 1MB torrents with many peers.
|
||||
|
||||
2007-01-17 zzz
|
||||
* Add new HTTP Proxy error message for non-http protocols
|
||||
|
||||
2007-01-17 zzz
|
||||
* Add note on Syndie index.html steering people to new Syndie
|
||||
|
||||
2007-01-16 zzz
|
||||
* i2psnark: Fix crash when autostart off and
|
||||
tcrrent started manually
|
||||
|
||||
2007-01-16 zzz
|
||||
* i2psnark: Fix bug caused by last i2psnark checkin
|
||||
(ConnectionAcceptor not started)
|
||||
* Don't start PeerCoordinator, ConnectionAcceptor,
|
||||
and TrackerClient unless starting torrent
|
||||
|
||||
2007-01-15 jrandom
|
||||
* small guard against unnecessary streaming lib reset packets
|
||||
(thanks Complication!)
|
||||
|
||||
2007-01-15 zzz
|
||||
* i2psnark: Add 'Stop All' link on web page
|
||||
* Add some links to trackers and forum on web page
|
||||
* Don't start tunnel if 'Autostart' unchecked
|
||||
* Fix torrent restart bug by reopening file descriptors
|
||||
|
||||
2007-01-14 zzz
|
||||
* i2psnark: Improvements for torrents with > 4 leechers:
|
||||
choke based on upload rate when seeding, and
|
||||
be smarter and fairer about rotating choked peers.
|
||||
* Handle two common i2psnark OOM situations rather
|
||||
than shutting down the whole thing.
|
||||
* Fix reporting to tracker of remaining bytes for
|
||||
torrents > 4GB (but ByteMonsoon still has a bug)
|
||||
|
||||
2006-10-29 zzz
|
||||
* i2psnark: Fix and enable generation of multifile torrents,
|
||||
print error if no tracker selected at create-torrent,
|
||||
fix stopping a torrent that hasn't started successfully,
|
||||
add eBook and GayTorrents trackers to form,
|
||||
web page formatting tweaks
|
||||
|
||||
* 2006-10-10 0.6.1.26 released
|
||||
|
||||
2006-10-29 Complication
|
||||
* Ensure we get NTP samples from more diverse sources
|
||||
(0.pool.ntp.org, 1.pool.ntp.org, etc)
|
||||
* Discard median-based peer skew calculator as framed average works,
|
||||
and adjusting its percentage can make it behave median-like
|
||||
* Require more data points (from at least 20 peers)
|
||||
before considering a peer skew measurement reliable
|
||||
|
||||
2006-10-10 jrandom
|
||||
* Removed the status display from the console, as its more confusing
|
||||
than informative (though the content is still displayed in the HTML)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
; TC's hosts.txt guaranteed freshness
|
||||
; $Id: hosts.txt,v 1.166 2006/01/23 10:29:36 cervantes Exp $
|
||||
; $Id: hosts.txt,v 1.169 2006-12-16 17:31:07 jrandom Exp $
|
||||
; changelog:
|
||||
; (1.191) added trac.i2p
|
||||
; (1.190) added archive.syndie.i2p
|
||||
; (1.189) added mtn.i2p
|
||||
; (1.188) added downloads.legion.i2p, politguy.i2p, ninja.i2p
|
||||
; (1.187) added hidden.i2p, bk1k.i2p, antipiracyagency.i2p
|
||||
; (1.186) added decadence.i2p, freedomarchives.i2p, closedshop.i2p
|
||||
@@ -498,4 +501,7 @@ antipiracyagency.i2p=lnOKgQBEcsbZHgsuN5rJQA5mXK59fWPoCtag-EGfgYkbO1YbbPAqUZHqF4a
|
||||
downloads.legion.i2p=p0eQqZscgqFvpoQtftNXFVRJpNzMkW1gx0cEmVz5xcpT195DxoVEwGlQ34mP4Da5nnUggcCaHzW9JBduqxiZU73quiO6VYeE65b70EhS0mRgsoVaU9-nsqo7ikYZ0-Rr6Qrhn32M6vktf4b2KljmpHgaBnJzMsFiMaEj3QuxGY8Q4tH6P34tgKiv2hYzZ8DGCj9bcmzzW0LX8XwA9tufi4XGM31qAZu~CiW14J5I8AwDUQRnyaWiZ8OzN~o3qTbkPyMAfXnAewcoA~GJPF9oAb-lHdESGeSEE38Krk2OYv3gQNUTiZcVaEck3VktqFmQiHCWDtAO0z8DIv9qmSjCI41w0MTCVlXNPRDO-YCE9JHlZv5zvS1~uCKltJwKGAHxHv~8N4oKMjJiB52XHXo3sWk503NTF-OK29ng~T4qfDQgEL6mm~jFhF3X-aruSkbn3OcRhWEgSJ2YdQYERnSwZn8gg4k78kvx02reisAHBN04UKa9YW95~Tz4S5Mqn8lrAAAA
|
||||
politguy.i2p=nyQ37u3uP7Zm5YoFXL4MFEjJH6iQhrMs0K~Bk57fEIYRGJIG31~tqScmDLOUPjxiwzHEsbbLJo-o9rll7744HMOHmlfNGegKMO-n7~pWCVRW2XtMQL17NnZl97bPiDdymTVJoAKrs2ZfEayDYiiBxKbUlbcnT51O0~aTymSmlyh1i0VQajbQOveEdN-QDiOWEdBLZCQx7lg4BXT78Sb76qQVj4c6jdYRxP~q1nL1XHyjp~qd0jjLFNeTqS8YPdEDJFWAKo7M1bIYV4SUcj40GzGIuWRnaSY-utizQFrRUC0NcdwZK7Mo1JivGC0TFtWFJsQ-xx5ix4vP4vYeQ8rGiyED32s1kwII9rCBu9DmLLTwGBjTX0yjXI4XEH2Q-C0fgIw6YniDYQj50a3q1KTkaqiXm~EtnWqkv9dGvSYY8-mfBlRKD8k1X83-MhycdZHNrsWhGxA~zpBmKcMVHD0CDbW2ZF6sHyS3wPZiQ2haeBJL6mm7ZWQT6J875w3SP-nnAAAA
|
||||
ninja.i2p=XhyN8MgL6DwWE98g2DJlDLHy~02g58IF14LTb472cmSLRj~cHv7wyi1mxy21vtf12oPWRquwMqpn4vJbKtnoQrLqRBgKAWtHgvUWOKPA8HqOmP4g9di3vGLefUNHUjkZWPXANBs-HwWH~~zPV0zwjN5keEZLVNQKfUkc0-qJ77zfxrDAPVjUBlyx1nlH7HcSxgzXS8qNlQuxWEqlqOiPushnalVFZSul-kVzG0Zo1PIQQHDKA1kpmwr2EX5xvCq0PgDZgj~xc3xkTzBMXC-m~NnmB1NRrH80lpY3nWMo-ySTVS7KcHH--zPUkvQhE2PCjLcSQsqpK2xsq0XEQOeAqoeDhosc3XxQDnDTmgBC0Bnus4N6RMBZgBRpniFT4ofwgGmFS1nDGkI-F4fLJSQ4f~P4sUR6HCZnwWIEvcr7lJgr26RP584nev9Dzhr4dq1hfTesShfluB19KJ17eBsimy1xIGDbiAeCSVtUjEviyb1lm7C~we3c0oCUUt2NvOGWAAAA
|
||||
mtn.i2p=RqXC4xbFK6t3g2wk9SO4RjY7mj1c0DmtMra5c1Md8t-DcNPSjQFmqT97pcZ5IR1JDKqyCO7RI~aATTTMPQexoEeqK9-6Poeh2RA1C81FzcA9sHvjLeg3eB1Cju-sE-IDeFntEvCC4w7wWnpmLzCfdXK7OjSK1wYc6OkqPOLVDEy-N-4UUPlZFWWUghpjBGXGayXz6JRKtoMIwhFQaiKdRvAs32ozM9RM0NWzrCaRLZBIQ6Gg1Ys1wF0-oBJgC4T4CN6SxJNaz9Dfw4GNtPyD6lq3S1osY1ccflm3itvUt3JC1J9ypoXzylBE5MuS-LTgbgbMdMFty07AoWB~EY8TwW8EQQO07GSzB7hm53u0iCEH44GexhKHtQP-hYbIr3mklo89BvfWIRGMTwUkAzYojzC-vOyIh16LWrQQhGbLvByKQSdWk9nInm3GEfqRVtSpuqd4m6iHzrBDZ3fvKjbuywot3hDNHitOHOedmBNA8neCzLkod8b0Z4xx~qRIEObxAAAA
|
||||
archive.syndie.i2p=iXX0DadZTJQpPr1to0OmQ4xokHgx1HYd5ec7~zIjQ80W~p4kRCYJmEzibH2Kn59Gi04SAXeA2O9i3bNqfGCQjsbz7UcjPGrW6-UrckXVXW67Moxp7QWY6i-aKuVYM3bqYxUL2mWvcDzJ8D0ecMpvasxhxwXpdFn2J6CGboMxeGV8R3hwwlNYbYoKgHr74qEJaIZpm1FrRWvNHV5cMv363iWnPy72XspQefk79-VOjPsxfummosU7gqlxl5teyiGKNzMs3G6iJyfVHO8IlKtdn~P~ET9p7zWlTPgV8NTyCVB-Wn5S3JMkMGOFZR7wSlxSwGFpTFQKc7mxVTtLZ5nWcV2OhvOIxRZ31RvGJZyVs562RC5aMfyqcM5IHQiZVlmkhzJKIy9VDw8tKayQtRM-xeN5k6Qr7iMmYIRORwuAODkYApoMD9a0eJ6ZYOSgBMOCSvYcwfT8axRY~GabiHm0QC82mo-nDgrUypGKtOPMI9MIqMTsb8Yl-UGWn6twBAIzAAAA
|
||||
trac.i2p=OBnF9NtkEsPij2F-lp3bWDVrJsPQQPdq6adlpq0N4BY1XRjtDBZl~EpDdk7roq49~ptKAQG2cNUeBEKIIrdlZhJio5pMwUl6YinizzkNTFfZipB5OKoB7PBulxkw-N9mKMhS1btd9ajcV8tiP3xiv7VSlgiDwbdKg1fmkvNrVrJnzkN3-ey2kebYnbh7jjU2gPFUl~CwSEkIi6AK9EfqmFR-DUVohyygqAY~fi4EMeTVXGUqftXSNFYUwpRJgFrWRPTurtZnJK5403q67oEk0eWrPIZ8ytJWSBfffAXL3ts~0O1FZeKXUccsAl33j70~lklSolNVLJ40y-6X5ZLWajmX0ONU3j0qI5A~7fgNgsg-vKypPDuzl8ug-D~BmhqdAf0sRYmziDVwTgU~WRB6IzhhXFR6CbwrGXdgOGg2qNT1eOnMwGo3SMMJ7kK88VC5LdYg2dyiyjZATuvT92QdZglrVQIeBqAehcFjOBuycC1ED3AOak8D9Xplj7V6hN-HAAAA
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2006-07-29 13:03:16 $">
|
||||
<i2p.release version="0.6.1.25" date="2006/07/29" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2007-02-15 18:25:04 $">
|
||||
<i2p.release version="0.6.1.28" date="2007/02/15" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<info>
|
||||
<appname>i2p</appname>
|
||||
<appversion>0.6.1.26</appversion>
|
||||
<appversion>0.6.1.28</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
</authors>
|
||||
|
||||
@@ -6,23 +6,21 @@
|
||||
<h1>Welcome to your eepsite</h1>
|
||||
|
||||
<p>This is your eepsite - simply edit the files under ./eepsite/docroot/
|
||||
and they'll be reachable. The 'key' to your eepsite that you need to
|
||||
give to other people is shown on the eepsite's I2PTunnel
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">configuration page</a>). </p>
|
||||
<p>
|
||||
If you have any standard java web applications (.war files) such as
|
||||
<a href="http://wiki.blojsom.com/wiki/display/blojsom/About%2Bblojsom">blojsom</a>
|
||||
or <a href="http://snipsnap.org/space/start">SnipSnap</a>, simply drop their .war
|
||||
file into ./eepsite/webapps/ and they'll be reachable at
|
||||
http://$yourEeepsite/warFileName/</p>
|
||||
|
||||
and they'll be reachable by others once you follow the instructions below.
|
||||
In I2P, eepsites are addressed using a 'key', which is represented as a really long Base64 string.
|
||||
(The 'key' is somewhat analogous to an IP address, and
|
||||
is shown on the eepsite's I2PTunnel
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">configuration page</a>).
|
||||
The instructions below detail how to assign a name like "mysite.i2p" to your key and
|
||||
start up your eepsite.</p>
|
||||
<p>You can also reach your eepsite locally through
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>. If you
|
||||
want to change the port number, edit the file ./eepsite/jetty.xml and
|
||||
update the I2PTunnel configuration accordingly.</p>
|
||||
|
||||
<h2>Step-by-step instructions for announcing your new eepsite to the I2P community</h2>
|
||||
Your eepsite is up and running but it will be hard for other people to find because it
|
||||
<h2>Step-by-step instructions for starting your new eepsite and announcing it to the I2P community</h2>
|
||||
Your eepsite is stopped by default.
|
||||
After you start it, it will be difficult for other people to find because it
|
||||
doesn't have a name and they don't have your really long Base64 key.
|
||||
You could just tell people that really long key but thankfully i2p has an address book
|
||||
and several easy ways to tell people about your eepsite. Here's detailed instructions.
|
||||
@@ -34,7 +32,13 @@
|
||||
Enter the new name for your eepsite on the
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel configuration page</a>
|
||||
where it says "Website name". This will replace the default "mysite.i2p".
|
||||
Also, check the "Auto Start" box. Your eepsite will now start every time you start your router.
|
||||
Be sure and click "Save".
|
||||
<li>Click the start button for your eepsite on the
|
||||
<a href="http://localhost:7657/i2ptunnel/index.jsp">main i2ptunnel configuration page</a>.
|
||||
You should now see "eepsite" listed under "Local Destinations" on the left side of the
|
||||
<a href="http://localhost:7657/index.jsp">I2P Router Console</a>.
|
||||
Your eepsite is now running.
|
||||
<li>Highlight the entire "Local destination" key on the
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel configuration page</a>.
|
||||
and copy it for
|
||||
@@ -68,8 +72,7 @@
|
||||
<li>Post a message on the <a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce forum</a>
|
||||
on <a href="http://forum.i2p/">forum.i2p</a>.
|
||||
<li>Tell people about it on the #i2p or #i2p-chat channels on IRC.
|
||||
<li>Put it in <a href="http://localhost:7657/syndie/post.jsp">new post</a> on
|
||||
<a href="http://localhost:7657/syndie/">Syndie</a>.
|
||||
<li>Put it in a new post on <a href="syndie.i2p.net">the new Syndie</a>.
|
||||
<li>Put it in <a href="http://ugha.i2p/EepsiteIndex">Ugha's Eepsite Index Wiki</a>
|
||||
</ul>
|
||||
Note that some sites recommend pasting in that really long destination key.
|
||||
|
||||
@@ -55,7 +55,7 @@ tunnel.3.i2cpHost=127.0.0.1
|
||||
tunnel.3.i2cpPort=7654
|
||||
tunnel.3.option.inbound.nickname=eepsite
|
||||
tunnel.3.option.outbound.nickname=eepsite
|
||||
tunnel.3.startOnLoad=true
|
||||
tunnel.3.startOnLoad=false
|
||||
|
||||
# postman's SMTP server - see www.postman.i2p
|
||||
tunnel.4.description=smtp server
|
||||
|
||||
21
news.xml
21
news.xml
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2006-09-13 22:16:53 $">
|
||||
<i2p.release version="0.6.1.25" date="2006/07/29" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2007-03-15 03:21:35 $">
|
||||
<i2p.release version="0.6.1.28" date="2007/02/15" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
@@ -10,15 +10,16 @@
|
||||
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting141"
|
||||
publiclogs="http://www.i2p.net/meeting141" />
|
||||
•
|
||||
2006-09-09: 0.6.1.25 <a href="http://dev.i2p/pipermail/i2p/2006-September/001306.html">released</a>
|
||||
with i2psnark, SusiDNS, NTP, and other fixes.
|
||||
2007-02-16: 0.6.1.27
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-February/001335.html">released</a>
|
||||
with
|
||||
<a href="http://forum.i2p/viewtopic.php?t=2027">i2psnark</a>
|
||||
and floodfill fixes and improvements.
|
||||
<br />
|
||||
•
|
||||
2006-09-12:
|
||||
<a href="http://www.i2p/meeting184">meeting log</a>
|
||||
<br />
|
||||
•
|
||||
2006-10-03:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2006-October/001309.html">status notes</a>
|
||||
2007-03-13:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-March/001338.html">status notes</a>
|
||||
and
|
||||
<a href="http://www.i2p/meeting202">meeting log</a>
|
||||
<br />
|
||||
</i2p.news>
|
||||
|
||||
@@ -3,7 +3,7 @@ grow over the next few minutes and you'll see some local "destinations" listed
|
||||
on the left (if not, <a href="#trouble">see below</a>). Once those show up,
|
||||
you can:</p>
|
||||
<ul>
|
||||
<li><b>blog anonymously</b> - check out <a href="/syndie/">Syndie</a></li>
|
||||
<li><b>blog anonymously</b> - check out <a href="http://syndie.i2p/">Syndie</a></li>
|
||||
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the
|
||||
server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
|
||||
IRC servers, but neither you nor they know where the other is.</li>
|
||||
@@ -44,9 +44,8 @@ you can:</p>
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>. Simply place your files in
|
||||
the <code>eepsite/docroot/</code> directory (or place any standard JSP/Servlet <code>.war</code>
|
||||
files under <code>eepsite/webapps</code>, or standard CGI script under <code>eepsite/cgi-bin</code>)
|
||||
and they'll show up. Your eepsite's
|
||||
<i>destination</i> (which uniquely and securely identifies it) can be found via the I2PTunnel
|
||||
<a href="/i2ptunnel/">configuration page</a> - on the details page of the "eepsite" tunnel.
|
||||
and they'll show up. After starting up an <a href="/i2ptunnel/">eepsite tunnel</a> pointing at it, your eepsite's
|
||||
<i>destination</i> (which uniquely and securely identifies it) will be visible.
|
||||
If you want other people to see your eepsite,
|
||||
you need to give them that really huge string. Just paste it into the
|
||||
<a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce</a> forum, add it to
|
||||
|
||||
@@ -225,7 +225,10 @@ public class Router {
|
||||
|
||||
public long getWhenStarted() { return _started; }
|
||||
/** wall clock uptime */
|
||||
public long getUptime() { return _context.clock().now() - _context.clock().getOffset() - _started; }
|
||||
public long getUptime() {
|
||||
if ( (_context == null) || (_context.clock() == null) ) return 1; // racing on startup
|
||||
return _context.clock().now() - _context.clock().getOffset() - _started;
|
||||
}
|
||||
|
||||
public RouterContext getContext() { return _context; }
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.466 $ $Date: 2006-10-08 17:53:00 $";
|
||||
public final static String VERSION = "0.6.1.26";
|
||||
public final static String ID = "$Revision: 1.497 $ $Date: 2007-03-15 13:26:06 $";
|
||||
public final static String VERSION = "0.6.1.28";
|
||||
public final static long BUILD = 0;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
|
||||
@@ -227,7 +227,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad
|
||||
}
|
||||
|
||||
/** list of the Hashes of currently known floodfill peers */
|
||||
List getFloodfillPeers() {
|
||||
public List getFloodfillPeers() {
|
||||
FloodfillPeerSelector sel = (FloodfillPeerSelector)getPeerSelector();
|
||||
return sel.selectFloodfillParticipants(getKBuckets());
|
||||
}
|
||||
|
||||
@@ -59,35 +59,6 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
|
||||
public int countActivePeers() { return (_manager == null ? 0 : _manager.countActivePeers()); }
|
||||
public int countActiveSendPeers() { return (_manager == null ? 0 : _manager.countActiveSendPeers()); }
|
||||
|
||||
/**
|
||||
* Median clock skew of connected peers in seconds, or null if we cannot answer.
|
||||
*/
|
||||
public Long getMedianPeerClockSkew() {
|
||||
if (_manager == null) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Returning null for median peer clock skew (no transport manager)!");
|
||||
return null;
|
||||
}
|
||||
Vector skews = _manager.getClockSkews();
|
||||
if (skews == null) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Returning null for median peer clock skew (no data)!");
|
||||
return null;
|
||||
}
|
||||
if (skews.size() < 5) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Returning null for median peer clock skew (only " + skews.size() + " peers)!");
|
||||
return null;
|
||||
}
|
||||
// Going to calculate, let's sort them
|
||||
Collections.sort(skews);
|
||||
// Pick out median
|
||||
Long medianPeerClockSkew = (Long) (skews.get(skews.size() / 2));
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Our median peer clock skew is " + medianPeerClockSkew + " s.");
|
||||
return medianPeerClockSkew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Framed average clock skew of connected peers in seconds, or null if we cannot answer.
|
||||
@@ -105,9 +76,9 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
_log.error("Returning null for framed average peer clock skew (no data)!");
|
||||
return null;
|
||||
}
|
||||
if (skews.size() < 5) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Returning null for framed average peer clock skew (only " + skews.size() + " peers)!");
|
||||
if (skews.size() < 20) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Returning null for framed average peer clock skew (only " + skews.size() + " peers)!");
|
||||
return null;
|
||||
}
|
||||
// Going to calculate, sort them
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.*;
|
||||
import java.util.zip.Adler32;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.RouterIdentity;
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.data.SessionKey;
|
||||
@@ -21,6 +22,7 @@ import net.i2p.data.i2np.I2NPMessageHandler;
|
||||
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.FIFOBandwidthLimiter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -350,6 +352,8 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
||||
infoMsg.beginSend();
|
||||
_context.statManager().addRateData("ntcp.infoMessageEnqueued", 1, 0);
|
||||
send(infoMsg);
|
||||
|
||||
enqueueFloodfillMessage(target);
|
||||
} else {
|
||||
if (_isInbound) {
|
||||
// ok, we shouldn't have enqueued it yet, as we havent received their info
|
||||
@@ -358,6 +362,39 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int PEERS_TO_FLOOD = 3;
|
||||
|
||||
/**
|
||||
* to prevent people from losing track of the floodfill peers completely, lets periodically
|
||||
* send those we are connected to references to the floodfill peers that we know
|
||||
*/
|
||||
private void enqueueFloodfillMessage(RouterInfo target) {
|
||||
FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)_context.netDb();
|
||||
List peers = fac.getFloodfillPeers();
|
||||
Collections.shuffle(peers);
|
||||
for (int i = 0; i < peers.size() && i < PEERS_TO_FLOOD; i++) {
|
||||
Hash peer = (Hash)peers.get(i);
|
||||
|
||||
// we already sent our own info, and no need to tell them about themselves
|
||||
if (peer.equals(_context.routerHash()) || peer.equals(target.calculateHash()))
|
||||
continue;
|
||||
|
||||
RouterInfo info = fac.lookupRouterInfoLocally(peer);
|
||||
|
||||
OutNetMessage infoMsg = new OutNetMessage(_context);
|
||||
infoMsg.setExpiration(_context.clock().now()+10*1000);
|
||||
DatabaseStoreMessage dsm = new DatabaseStoreMessage(_context);
|
||||
dsm.setKey(peer);
|
||||
dsm.setRouterInfo(info);
|
||||
infoMsg.setMessage(dsm);
|
||||
infoMsg.setPriority(100);
|
||||
infoMsg.setTarget(target);
|
||||
infoMsg.beginSend();
|
||||
_context.statManager().addRateData("ntcp.floodInfoMessageEnqueued", 1, 0);
|
||||
send(infoMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clockSkew alice's clock minus bob's clock in seconds (may be negative, obviously, but |val| should
|
||||
@@ -545,12 +582,22 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
||||
return;
|
||||
}
|
||||
//throw new RuntimeException("We should not be preparing a write while we still have one pending");
|
||||
if (_outbound.size() > 0) {
|
||||
if (queueTime() > 3*1000) { // don't stall low-priority messages
|
||||
msg = (OutNetMessage)_outbound.remove(0);
|
||||
_currentOutbound = msg;
|
||||
} else {
|
||||
return;
|
||||
Iterator it = _outbound.iterator();
|
||||
for (int i = 0; it.hasNext() && i < 75; i++) { //arbitrary bound
|
||||
OutNetMessage mmsg = (OutNetMessage) it.next();
|
||||
if (msg == null || mmsg.getPriority() > msg.getPriority())
|
||||
msg = mmsg;
|
||||
}
|
||||
if (msg == null)
|
||||
return;
|
||||
// if (_outbound.indexOf(msg) > 0)
|
||||
// _log.debug("Priority message sent, pri = " + msg.getPriority() + " pos = " + _outbound.indexOf(msg) + "/" +_outbound.size());
|
||||
_outbound.remove(msg);
|
||||
}
|
||||
_currentOutbound = msg;
|
||||
}
|
||||
|
||||
msg.beginTransmission();
|
||||
|
||||
@@ -87,6 +87,7 @@ public class NTCPTransport extends TransportImpl {
|
||||
_context.statManager().createRateStat("ntcp.inboundEstablished", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.inboundEstablishedDuplicate", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.infoMessageEnqueued", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.floodInfoMessageEnqueued", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.invalidDH", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.invalidHXY", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
_context.statManager().createRateStat("ntcp.invalidHXxorBIH", "", "ntcp", new long[] { 60*1000, 10*60*1000 });
|
||||
|
||||
@@ -156,7 +156,8 @@ class BuildExecutor implements Runnable {
|
||||
|
||||
// Trim the number of allowed tunnels for overload,
|
||||
// initiate a tunnel drop on severe overload
|
||||
allowed = trimForOverload(allowed,concurrent);
|
||||
// tunnel building is high priority, don't do this
|
||||
// allowed = trimForOverload(allowed,concurrent);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
@@ -168,6 +169,7 @@ class BuildExecutor implements Runnable {
|
||||
/**
|
||||
* Don't even try to build tunnels if we're saturated
|
||||
*/
|
||||
/*
|
||||
private int trimForOverload(int allowed, int concurrent) {
|
||||
|
||||
// dont include the inbound rates when throttling tunnel building, since
|
||||
@@ -221,7 +223,7 @@ class BuildExecutor implements Runnable {
|
||||
// No overload, allow as requested
|
||||
return(allowed);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
|
||||
Reference in New Issue
Block a user