forked from I2P_Developers/i2p.i2p
Compare commits
31 Commits
i2p_0_6_1_
...
i2p_0_6_1_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1c66543938 | ||
![]() |
53ab3c472e | ||
![]() |
a4b221fa71 | ||
![]() |
e3e1d0842d | ||
![]() |
99b5bf9609 | ||
![]() |
da10fe0df7 | ||
![]() |
9fd5ba7b2d | ||
![]() |
05b5df9d76 | ||
![]() |
5c1dc79767 | ||
![]() |
4acd2996c5 | ||
![]() |
16fa6a89bc | ||
![]() |
2a72e8574b | ||
![]() |
d4a1bcf28f | ||
![]() |
409b71def5 | ||
![]() |
2dc5fbda02 | ||
![]() |
71aaf03d09 | ||
![]() |
30c99e630b | ||
![]() |
445b39171a | ||
![]() |
571c2d6047 | ||
![]() |
42ff763933 | ||
![]() |
727edc3ff9 | ||
![]() |
82a4758a0a | ||
![]() |
915914ebb3 | ||
![]() |
c438b56378 | ||
![]() |
307ccfb1b4 | ||
![]() |
34e23259b4 | ||
![]() |
036802d66a | ||
![]() |
6a7dbc8e3a | ||
![]() |
cf4a9ffc27 | ||
![]() |
6ef4adf318 | ||
![]() |
f84c9bf3b1 |
@@ -32,6 +32,7 @@ public class BitField
|
||||
|
||||
private final byte[] bitfield;
|
||||
private final int size;
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Creates a new BitField that represents <code>size</code> unset bits.
|
||||
@@ -41,6 +42,7 @@ public class BitField
|
||||
this.size = size;
|
||||
int arraysize = ((size-1)/8)+1;
|
||||
bitfield = new byte[arraysize];
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +62,11 @@ public class BitField
|
||||
// XXX - More correct would be to check that unused bits are
|
||||
// cleared or clear them explicitly ourselves.
|
||||
System.arraycopy(bitfield, 0, this.bitfield, 0, arraysize);
|
||||
|
||||
this.count = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
if (get(i))
|
||||
this.count++;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +102,10 @@ public class BitField
|
||||
throw new IndexOutOfBoundsException(Integer.toString(bit));
|
||||
int index = bit/8;
|
||||
int mask = 128 >> (bit % 8);
|
||||
bitfield[index] |= mask;
|
||||
if ((bitfield[index] & mask) == 0) {
|
||||
count++;
|
||||
bitfield[index] |= mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,6 +124,22 @@ public class BitField
|
||||
return (bitfield[index] & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of set bits.
|
||||
*/
|
||||
public int count()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all bits are set.
|
||||
*/
|
||||
public boolean complete()
|
||||
{
|
||||
return count >= size;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
// Not very efficient
|
||||
@@ -129,4 +155,5 @@ public class BitField
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -101,6 +101,8 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
if (opts.getProperty("inbound.nickname") == null)
|
||||
opts.setProperty("inbound.nickname", "I2PSnark");
|
||||
if (opts.getProperty("outbound.nickname") == null)
|
||||
opts.setProperty("outbound.nickname", "I2PSnark");
|
||||
if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
|
||||
opts.setProperty("i2p.streaming.inactivityTimeout", "90000");
|
||||
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
|
||||
|
@@ -54,8 +54,8 @@ 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
|
||||
final static long CHECK_PERIOD = PeerCoordinator.CHECK_PERIOD; // 40 seconds
|
||||
final static int RATE_DEPTH = PeerCoordinator.RATE_DEPTH; // 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};
|
||||
|
||||
@@ -493,33 +493,24 @@ public class Peer implements Comparable
|
||||
|
||||
/**
|
||||
* 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 s.bitfield.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;
|
||||
return s.bitfield.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -237,6 +237,8 @@ public class PeerCoordinator implements PeerListener
|
||||
peer.disconnect();
|
||||
removePeerFromPieces(peer);
|
||||
}
|
||||
// delete any saved orphan partial piece
|
||||
savedRequest = null;
|
||||
}
|
||||
|
||||
public void connected(Peer peer)
|
||||
@@ -263,6 +265,7 @@ public class PeerCoordinator implements PeerListener
|
||||
{
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Already connected to: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
|
||||
// toDisconnect = peer to get out of synchronized(peers)
|
||||
peer.disconnect(false); // Don't deregister this connection/peer.
|
||||
}
|
||||
else
|
||||
@@ -357,7 +360,6 @@ public class PeerCoordinator implements PeerListener
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer peer = (Peer)it.next();
|
||||
boolean remove = false;
|
||||
if (peer.isChoking() && peer.isInterested())
|
||||
{
|
||||
count++;
|
||||
@@ -691,6 +693,8 @@ public class PeerCoordinator implements PeerListener
|
||||
private long savedRequestTime = 0;
|
||||
public void savePeerPartial(PeerState state)
|
||||
{
|
||||
if (halted)
|
||||
return;
|
||||
Request req = state.getPartialRequest();
|
||||
if (req == null)
|
||||
return;
|
||||
@@ -791,7 +795,7 @@ public class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
public void markUnrequested(Peer peer)
|
||||
{
|
||||
if (peer.state == null)
|
||||
if (halted || peer.state == null)
|
||||
return;
|
||||
int[] arr = peer.state.getRequestedPieces();
|
||||
for (int i = 0; arr[i] >= 0; i++)
|
||||
|
@@ -468,6 +468,8 @@ public class Snark
|
||||
pc.halt();
|
||||
Storage st = storage;
|
||||
if (st != null) {
|
||||
if (storage.changed)
|
||||
SnarkManager.instance().saveTorrentStatus(storage.getMetaInfo(), storage.getBitField());
|
||||
try {
|
||||
storage.close();
|
||||
} catch (IOException ioe) {
|
||||
|
@@ -3,6 +3,7 @@ package org.klomp.snark;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
@@ -30,6 +31,8 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
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_META_PREFIX = "i2psnark.zmeta.";
|
||||
public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
|
||||
|
||||
public static final String PROP_AUTO_START = "i2snark.autoStart";
|
||||
public static final String DEFAULT_AUTO_START = "false";
|
||||
@@ -271,7 +274,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
public void saveConfig() {
|
||||
try {
|
||||
DataHelper.storeProps(_config, new File(_configFile));
|
||||
synchronized (_configFile) {
|
||||
DataHelper.storeProps(_config, new File(_configFile));
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
addMessage("Unable to save the config to '" + _configFile + "'");
|
||||
}
|
||||
@@ -361,7 +366,97 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp for a torrent from the config file
|
||||
*/
|
||||
public long getSavedTorrentTime(MetaInfo metainfo) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
String infohash = Base64.encode(ih);
|
||||
infohash = infohash.replace('=', '$');
|
||||
String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
|
||||
if (time == null)
|
||||
return 0;
|
||||
int comma = time.indexOf(',');
|
||||
if (comma <= 0)
|
||||
return 0;
|
||||
time = time.substring(0, comma);
|
||||
try { return Long.parseLong(time); } catch (NumberFormatException nfe) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the saved bitfield for a torrent from the config file.
|
||||
* Convert "." to a full bitfield.
|
||||
*/
|
||||
public BitField getSavedTorrentBitField(MetaInfo metainfo) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
String infohash = Base64.encode(ih);
|
||||
infohash = infohash.replace('=', '$');
|
||||
String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
|
||||
if (bf == null)
|
||||
return null;
|
||||
int comma = bf.indexOf(',');
|
||||
if (comma <= 0)
|
||||
return null;
|
||||
bf = bf.substring(comma + 1).trim();
|
||||
int len = metainfo.getPieces();
|
||||
if (bf.equals(".")) {
|
||||
BitField bitfield = new BitField(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
bitfield.set(i);
|
||||
return bitfield;
|
||||
}
|
||||
byte[] bitfield = Base64.decode(bf);
|
||||
if (bitfield == null)
|
||||
return null;
|
||||
if (bitfield.length * 8 < len)
|
||||
return null;
|
||||
return new BitField(bitfield, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the completion status of a torrent and the current time in the config file
|
||||
* in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield".
|
||||
* The config file property key is appended with the Base64 of the infohash,
|
||||
* with the '=' changed to '$' since a key can't contain '='.
|
||||
* The time is a standard long converted to string.
|
||||
* The status is either a bitfield converted to Base64 or "." for a completed
|
||||
* torrent to save space in the config file and in memory.
|
||||
*/
|
||||
public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
String infohash = Base64.encode(ih);
|
||||
infohash = infohash.replace('=', '$');
|
||||
String now = "" + System.currentTimeMillis();
|
||||
String bfs;
|
||||
if (bitfield.complete()) {
|
||||
bfs = ".";
|
||||
} else {
|
||||
byte[] bf = bitfield.getFieldBytes();
|
||||
bfs = Base64.encode(bf);
|
||||
}
|
||||
_config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the status of a torrent from the config file.
|
||||
* This may help the config file from growing too big.
|
||||
*/
|
||||
public void removeTorrentStatus(MetaInfo metainfo) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
String infohash = Base64.encode(ih);
|
||||
infohash = infohash.replace('=', '$');
|
||||
_config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
private String locked_validateTorrent(MetaInfo info) throws IOException {
|
||||
String announce = info.getAnnounce();
|
||||
// basic validation of url
|
||||
if ((!announce.startsWith("http://")) ||
|
||||
(announce.indexOf(".i2p/") < 0))
|
||||
return "Non-i2p tracker in " + info.getName() + ", deleting it";
|
||||
List files = info.getFiles();
|
||||
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
|
||||
return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it";
|
||||
@@ -426,6 +521,8 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
if (torrent != null) {
|
||||
File torrentFile = new File(filename);
|
||||
torrentFile.delete();
|
||||
if (torrent.storage != null)
|
||||
removeTorrentStatus(torrent.storage.getMetaInfo());
|
||||
addMessage("Torrent removed: '" + torrentFile.getName() + "'");
|
||||
}
|
||||
}
|
||||
@@ -496,25 +593,29 @@ 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"
|
||||
"Postman", "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=http://tracker.postman.i2p/"
|
||||
, "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
|
||||
, "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
|
||||
, "NickyB", "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=http://nickyb.i2p/bittorrent/"
|
||||
, "Orion", "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=http://orion.i2p/bt/"
|
||||
, "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
|
||||
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
|
||||
};
|
||||
|
||||
/** comma delimited list of name=announceURL for the trackers to be displayed */
|
||||
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
|
||||
public static final String PROP_TRACKERS = "i2psnark.trackers";
|
||||
/** unordered map of announceURL to name */
|
||||
private static Map trackerMap = null;
|
||||
/** sorted map of name to announceURL=baseURL */
|
||||
public Map getTrackers() {
|
||||
HashMap rv = new HashMap();
|
||||
if (trackerMap != null) // only do this once, can't be updated while running
|
||||
return trackerMap;
|
||||
Map rv = new TreeMap();
|
||||
String trackers = _config.getProperty(PROP_TRACKERS);
|
||||
if ( (trackers == null) || (trackers.trim().length() <= 0) )
|
||||
trackers = _context.getProperty(PROP_TRACKERS);
|
||||
if ( (trackers == null) || (trackers.trim().length() <= 0) ) {
|
||||
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2)
|
||||
rv.put(DEFAULT_TRACKERS[i+1], DEFAULT_TRACKERS[i]);
|
||||
rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]);
|
||||
} else {
|
||||
StringTokenizer tok = new StringTokenizer(trackers, ",");
|
||||
while (tok.hasMoreTokens()) {
|
||||
@@ -525,11 +626,12 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
String name = pair.substring(0, split).trim();
|
||||
String url = pair.substring(split+1).trim();
|
||||
if ( (name.length() > 0) && (url.length() > 0) )
|
||||
rv.put(url, name);
|
||||
rv.put(name, url);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
trackerMap = rv;
|
||||
return trackerMap;
|
||||
}
|
||||
|
||||
private static class TorrentFilenameFilter implements FilenameFilter {
|
||||
|
@@ -45,6 +45,7 @@ public class Storage
|
||||
// XXX - Not always set correctly
|
||||
int piece_size;
|
||||
int pieces;
|
||||
boolean changed;
|
||||
|
||||
/** The default piece size. */
|
||||
private static int MIN_PIECE_SIZE = 256*1024;
|
||||
@@ -285,6 +286,10 @@ public class Storage
|
||||
public void check(String rootDir) throws IOException
|
||||
{
|
||||
File base = new File(rootDir, filterName(metainfo.getName()));
|
||||
// look for saved bitfield and timestamp in the config file
|
||||
long savedTime = SnarkManager.instance().getSavedTorrentTime(metainfo);
|
||||
BitField savedBitField = SnarkManager.instance().getSavedTorrentBitField(metainfo);
|
||||
boolean useSavedBitField = savedTime > 0 && savedBitField != null;
|
||||
|
||||
List files = metainfo.getFiles();
|
||||
if (files == null)
|
||||
@@ -298,6 +303,11 @@ public class Storage
|
||||
rafs = new RandomAccessFile[1];
|
||||
names = new String[1];
|
||||
lengths[0] = metainfo.getTotalLength();
|
||||
if (useSavedBitField) {
|
||||
long lm = base.lastModified();
|
||||
if (lm <= 0 || lm > savedTime)
|
||||
useSavedBitField = false;
|
||||
}
|
||||
if (base.exists() && !base.canWrite()) // hope we can get away with this, if we are only seeding...
|
||||
rafs[0] = new RandomAccessFile(base, "r");
|
||||
else
|
||||
@@ -322,6 +332,11 @@ public class Storage
|
||||
File f = createFileFromNames(base, (List)files.get(i));
|
||||
lengths[i] = ((Long)ls.get(i)).longValue();
|
||||
total += lengths[i];
|
||||
if (useSavedBitField) {
|
||||
long lm = base.lastModified();
|
||||
if (lm <= 0 || lm > savedTime)
|
||||
useSavedBitField = false;
|
||||
}
|
||||
if (f.exists() && !f.canWrite()) // see above re: only seeding
|
||||
rafs[i] = new RandomAccessFile(f, "r");
|
||||
else
|
||||
@@ -335,7 +350,14 @@ public class Storage
|
||||
throw new IOException("File lengths do not add up "
|
||||
+ total + " != " + metalength);
|
||||
}
|
||||
checkCreateFiles();
|
||||
if (useSavedBitField) {
|
||||
bitfield = savedBitField;
|
||||
needed = metainfo.getPieces() - bitfield.count();
|
||||
Snark.debug("Found saved state and files unchanged, skipping check", Snark.NOTICE);
|
||||
} else {
|
||||
checkCreateFiles();
|
||||
SnarkManager.instance().saveTorrentStatus(metainfo, bitfield);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,7 +376,7 @@ public class Storage
|
||||
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...
|
||||
if (complete() || !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");
|
||||
@@ -372,7 +394,7 @@ public class Storage
|
||||
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
|
||||
if (complete() || !f.canWrite()) // see above re: only seeding
|
||||
rafs[i] = new RandomAccessFile(f, "r");
|
||||
else
|
||||
rafs[i] = new RandomAccessFile(f, "rw");
|
||||
@@ -517,6 +539,7 @@ public class Storage
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,6 +627,7 @@ public class Storage
|
||||
}
|
||||
}
|
||||
|
||||
changed = true;
|
||||
if (complete) {
|
||||
// listener.storageCompleted(this);
|
||||
// do we also need to close all of the files and reopen
|
||||
@@ -623,6 +647,8 @@ public class Storage
|
||||
listener.setWantedPieces(this);
|
||||
Snark.debug("WARNING: Not really done, missing " + needed
|
||||
+ " pieces", Snark.WARNING);
|
||||
} else {
|
||||
SnarkManager.instance().saveTorrentStatus(metainfo, bitfield);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,7 @@ public class TrackerClient extends I2PThread
|
||||
private static final String STARTED_EVENT = "started";
|
||||
private static final String COMPLETED_EVENT = "completed";
|
||||
private static final String STOPPED_EVENT = "stopped";
|
||||
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
|
||||
|
||||
private final static int SLEEP = 5; // 5 minutes.
|
||||
private final static int DELAY_MIN = 2000; // 2 secs.
|
||||
@@ -151,6 +152,10 @@ public class TrackerClient extends I2PThread
|
||||
("WARNING: Could not contact tracker at '"
|
||||
+ announce + "': " + ioe, Snark.WARNING);
|
||||
coordinator.trackerProblems = ioe.getMessage();
|
||||
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
|
||||
stop = true;
|
||||
coordinator.snark.stopTorrent();
|
||||
}
|
||||
}
|
||||
|
||||
if (stop)
|
||||
@@ -254,6 +259,10 @@ public class TrackerClient extends I2PThread
|
||||
("WARNING: Could not contact tracker at '"
|
||||
+ announce + "': " + ioe, Snark.WARNING);
|
||||
coordinator.trackerProblems = ioe.getMessage();
|
||||
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
|
||||
stop = true;
|
||||
coordinator.snark.stopTorrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,6 +307,7 @@ public class TrackerClient extends I2PThread
|
||||
if (fetched == null) {
|
||||
throw new IOException("Error fetching " + s);
|
||||
}
|
||||
fetched.deleteOnExit();
|
||||
|
||||
InputStream in = null;
|
||||
try {
|
||||
@@ -325,7 +335,7 @@ public class TrackerClient extends I2PThread
|
||||
* Very lazy byte[] to URL encoder. Just encodes everything, even
|
||||
* "normal" chars.
|
||||
*/
|
||||
static String urlencode(byte[] bs)
|
||||
public static String urlencode(byte[] bs)
|
||||
{
|
||||
StringBuffer sb = new StringBuffer(bs.length*3);
|
||||
for (int i = 0; i < bs.length; i++)
|
||||
|
@@ -67,14 +67,23 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("<tr><td width=\"20%\" class=\"snarkTitle\" valign=\"top\" align=\"left\">");
|
||||
out.write("I2PSnark<br />\n");
|
||||
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("<tr><td><a href=\"" + req.getRequestURI() + peerString + "\" class=\"snarkRefresh\">Refresh</a>\n");
|
||||
out.write("<td><a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\">Forum</a>\n");
|
||||
int count = 0;
|
||||
Map trackers = _manager.getTrackers();
|
||||
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String baseURL = (String)trackers.get(name);
|
||||
int e = baseURL.indexOf('=');
|
||||
if (e < 0)
|
||||
continue;
|
||||
baseURL = baseURL.substring(e + 1);
|
||||
if (count++ % 2 == 0)
|
||||
out.write("<tr>");
|
||||
out.write("<td><a href=\"" + baseURL + "\" class=\"snarkRefresh\">" + name + "</a>\n");
|
||||
}
|
||||
if (count % 2 == 1)
|
||||
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();
|
||||
@@ -335,7 +344,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 static final int MAX_DISPLAYED_ERROR_LENGTH = 40;
|
||||
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);
|
||||
@@ -388,15 +397,15 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String statusString = "Unknown";
|
||||
if (err != null) {
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "TrackerErr (" +
|
||||
statusString = "<a title=\"" + err + "\">TrackerErr</a> (" +
|
||||
curPeers + "/" + knownPeers +
|
||||
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
|
||||
else if (isRunning)
|
||||
statusString = "TrackerErr (" + curPeers + "/" + knownPeers + " peers)";
|
||||
statusString = "<a title=\"" + err + "\">TrackerErr (" + curPeers + "/" + knownPeers + " peers)";
|
||||
else {
|
||||
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
||||
err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "...";
|
||||
statusString = "TrackerErr (" + err + ")";
|
||||
statusString = "TrackerErr<br />(" + err + ")";
|
||||
}
|
||||
} else if (remaining <= 0) {
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
@@ -438,6 +447,25 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write(filename);
|
||||
if (remaining == 0)
|
||||
out.write("</a>");
|
||||
// temporarily hardcoded for postman and anonymity, requires bytemonsoon patch for lookup by info_hash
|
||||
String announce = snark.meta.getAnnounce();
|
||||
if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr")) {
|
||||
Map trackers = _manager.getTrackers();
|
||||
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String baseURL = (String)trackers.get(name);
|
||||
if (!baseURL.startsWith(announce))
|
||||
continue;
|
||||
int e = baseURL.indexOf('=');
|
||||
if (e < 0)
|
||||
continue;
|
||||
baseURL = baseURL.substring(e + 1);
|
||||
out.write(" (<a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash=");
|
||||
out.write(TrackerClient.urlencode(snark.meta.getInfoHash()));
|
||||
out.write("\" title=\"" + name + " Tracker\">Details</a>)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.write("</td>\n\t");
|
||||
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
|
||||
@@ -500,7 +528,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
client = "Azureus";
|
||||
else
|
||||
client = "Unknown";
|
||||
out.write("<font size=-1>" + client + "</font> <tt>" + peer.toString().substring(5, 9) + "</tt>");
|
||||
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");
|
||||
@@ -519,20 +547,32 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
if (remaining > 0) {
|
||||
if (peer.isInteresting() && !peer.isChoked())
|
||||
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("<font size=-1>" + formatSize(peer.getDownloadRate()) + "ps</font></font>");
|
||||
} else {
|
||||
out.write("<font color=#a00000><font size=-1><a title=\"");
|
||||
if (!peer.isInteresting())
|
||||
out.write("Uninteresting\">");
|
||||
else
|
||||
out.write("Choked\">");
|
||||
out.write(formatSize(peer.getDownloadRate()) + "ps</a></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())
|
||||
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("<font size=-1>" + formatSize(peer.getUploadRate()) + "ps</font></font>");
|
||||
} else {
|
||||
out.write("<font color=#a00000><font size=-1><a title=\"");
|
||||
if (!peer.isInterested())
|
||||
out.write("Uninterested\">");
|
||||
else
|
||||
out.write("Choking\">");
|
||||
out.write(formatSize(peer.getUploadRate()) + "ps</a></font></font>");
|
||||
}
|
||||
}
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
@@ -578,12 +618,14 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
+ "<input type=\"text\" name=\"baseFile\" size=\"20\" value=\"" + baseFile
|
||||
+ "\" title=\"File to seed (must be within the specified path)\" /><br />\n");
|
||||
out.write("Tracker: <select name=\"announceURL\"><option value=\"\">Select a tracker</option>\n");
|
||||
Map trackers = sort(_manager.getTrackers());
|
||||
Map trackers = _manager.getTrackers();
|
||||
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String announceURL = (String)trackers.get(name);
|
||||
// we inject whitespace in sort(...) to guarantee uniqueness, but we can strip it off here
|
||||
out.write("\t<option value=\"" + announceURL + "\">" + name.trim() + "</option>\n");
|
||||
int e = announceURL.indexOf('=');
|
||||
if (e > 0)
|
||||
announceURL = announceURL.substring(0, e);
|
||||
out.write("\t<option value=\"" + announceURL + "\">" + name + "</option>\n");
|
||||
}
|
||||
out.write("</select>\n");
|
||||
out.write("or <input type=\"text\" name=\"announceURLOther\" size=\"50\" value=\"http://\" " +
|
||||
@@ -592,18 +634,6 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("</form>\n</span>\n");
|
||||
}
|
||||
|
||||
private Map sort(Map trackers) {
|
||||
TreeMap rv = new TreeMap();
|
||||
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String url = (String)iter.next();
|
||||
String name = (String)trackers.get(url);
|
||||
while (rv.containsKey(name))
|
||||
name = name + " ";
|
||||
rv.put(name, url);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void writeConfigForm(PrintWriter out, HttpServletRequest req) throws IOException {
|
||||
String uri = req.getRequestURI();
|
||||
String dataDir = _manager.getDataDir().getAbsolutePath();
|
||||
|
@@ -597,6 +597,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private static String jumpServers[] = {"http://orion.i2p/jump/",
|
||||
"http://trevorreznik.i2p/cgi-bin/jump.php?hostname="
|
||||
};
|
||||
private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
||||
boolean usingWWWProxy, String wwwProxy, boolean showAddrHelper) throws IOException {
|
||||
if (out != null) {
|
||||
@@ -615,11 +618,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
out.write("</a>".getBytes());
|
||||
if (usingWWWProxy) out.write(("<br>WWW proxy: " + wwwProxy).getBytes());
|
||||
if (showAddrHelper) {
|
||||
out.write("<br><br>Click below to try an address helper link:<br><br><a href=\"http://orion.i2p/jump/".getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("\">http://orion.i2p/jump/".getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
out.write("<br><br>Click a link below to look for an address helper by using a \"jump\" service:<br>".getBytes());
|
||||
for (int i = 0; i < jumpServers.length; i++) {
|
||||
out.write("<br><a href=\"".getBytes());
|
||||
out.write(jumpServers[i].getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("\">".getBytes());
|
||||
out.write(jumpServers[i].getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write("</div><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
|
@@ -41,6 +41,8 @@ public class ConfigNetHandler extends FormHandler {
|
||||
private String _ntcpPort;
|
||||
private String _tcpPort;
|
||||
private String _udpPort;
|
||||
private boolean _ntcpAutoIP;
|
||||
private boolean _ntcpAutoPort;
|
||||
private String _inboundRate;
|
||||
private String _inboundBurstRate;
|
||||
private String _inboundBurst;
|
||||
@@ -70,6 +72,8 @@ public class ConfigNetHandler extends FormHandler {
|
||||
public void setDynamicKeys(String moo) { _dynamicKeys = true; }
|
||||
public void setUpdateratesonly(String moo) { _ratesOnly = true; }
|
||||
public void setEnableloadtesting(String moo) { _enableLoadTesting = true; }
|
||||
public void setNtcpAutoIP(String moo) { _ntcpAutoIP = true; }
|
||||
public void setNtcpAutoPort(String moo) { _ntcpAutoPort = true; }
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
_hostname = (hostname != null ? hostname.trim() : null);
|
||||
@@ -142,27 +146,49 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_ntcpHostname != null) && (_ntcpHostname.length() > 0) && (_ntcpPort != null) && (_ntcpPort.length() > 0) ) {
|
||||
String oldHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
|
||||
String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
if ( (oldHost == null) || (!oldHost.equalsIgnoreCase(_ntcpHostname)) ||
|
||||
(oldPort == null) || (!oldPort.equalsIgnoreCase(_ntcpPort)) ) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME, _ntcpHostname);
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT, _ntcpPort);
|
||||
addFormNotice("Updating inbound TCP settings from " + oldHost + ":" + oldPort
|
||||
+ " to " + _ntcpHostname + ":" + _ntcpPort);
|
||||
restartRequired = true;
|
||||
}
|
||||
} else {
|
||||
String oldHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
|
||||
String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
if ( (oldHost != null) || (oldPort != null) ) {
|
||||
// Normalize some things to make the following code a little easier...
|
||||
String oldNHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
|
||||
if (oldNHost == null) oldNHost = "";
|
||||
String oldNPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
if (oldNPort == null) oldNPort = "";
|
||||
String sAutoHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_IP);
|
||||
String sAutoPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_PORT);
|
||||
boolean oldAutoHost = "true".equalsIgnoreCase(sAutoHost);
|
||||
boolean oldAutoPort = "true".equalsIgnoreCase(sAutoPort);
|
||||
if (_ntcpHostname == null) _ntcpHostname = "";
|
||||
if (_ntcpPort == null) _ntcpPort = "";
|
||||
|
||||
if (oldAutoHost != _ntcpAutoIP || ! oldNHost.equalsIgnoreCase(_ntcpHostname)) {
|
||||
if (_ntcpAutoIP) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_IP, "true");
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
addFormNotice("Updating inbound TCP settings from " + oldHost + ":" + oldPort
|
||||
+ " so that we no longer receive inbound TCP connections");
|
||||
restartRequired = true;
|
||||
addFormNotice("Updating inbound TCP address to auto");
|
||||
} else if (_ntcpHostname.length() > 0) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME, _ntcpHostname);
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_IP);
|
||||
addFormNotice("Updating inbound TCP address to " + _ntcpHostname);
|
||||
} else {
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_IP);
|
||||
addFormNotice("Disabling inbound TCP");
|
||||
}
|
||||
restartRequired = true;
|
||||
}
|
||||
if (oldAutoPort != _ntcpAutoPort || ! oldNPort.equals(_ntcpPort)) {
|
||||
if ( _ntcpAutoPort ) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_PORT, "true");
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
addFormNotice("Updating inbound TCP port to auto");
|
||||
} else if (_ntcpPort.length() > 0) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT, _ntcpPort);
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_PORT);
|
||||
addFormNotice("Updating inbound TCP port to " + _ntcpPort);
|
||||
} else {
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_PORT);
|
||||
_context.router().removeConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_AUTO_PORT);
|
||||
addFormNotice("Disabling inbound TCP");
|
||||
}
|
||||
restartRequired = true;
|
||||
}
|
||||
|
||||
if ( (_udpPort != null) && (_udpPort.length() > 0) ) {
|
||||
|
@@ -50,6 +50,8 @@ public class ConfigNetHelper {
|
||||
}
|
||||
public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
|
||||
public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
|
||||
public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoip";
|
||||
public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoport";
|
||||
public String getNtcphostname() {
|
||||
String hostname = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
|
||||
if (hostname == null) return "";
|
||||
@@ -69,6 +71,26 @@ public class ConfigNetHelper {
|
||||
return ua.toString();
|
||||
}
|
||||
|
||||
public String getUdpIP() {
|
||||
RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
|
||||
if (addr == null)
|
||||
return "unknown";
|
||||
UDPAddress ua = new UDPAddress(addr);
|
||||
if (ua.getHost() == null)
|
||||
return "unknown";
|
||||
return ua.getHost();
|
||||
}
|
||||
|
||||
public String getUdpPort() {
|
||||
RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
|
||||
if (addr == null)
|
||||
return "unknown";
|
||||
UDPAddress ua = new UDPAddress(addr);
|
||||
if (ua.getPort() <= 0)
|
||||
return "unknown";
|
||||
return "" + ua.getPort();
|
||||
}
|
||||
|
||||
public String getEnableTimeSyncChecked() {
|
||||
String disabled = _context.getProperty(Timestamper.PROP_DISABLED, "false");
|
||||
if ( (disabled != null) && ("true".equalsIgnoreCase(disabled)) )
|
||||
@@ -93,6 +115,22 @@ public class ConfigNetHelper {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getTcpAutoPortChecked() {
|
||||
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_PORT, "false");
|
||||
if ( (enabled != null) && ("true".equalsIgnoreCase(enabled)) )
|
||||
return " checked ";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getTcpAutoIPChecked() {
|
||||
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "false");
|
||||
if ( (enabled != null) && ("true".equalsIgnoreCase(enabled)) )
|
||||
return " checked ";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getRequireIntroductionsChecked() {
|
||||
short status = _context.commSystem().getReachabilityStatus();
|
||||
switch (status) {
|
||||
@@ -236,4 +274,23 @@ public class ConfigNetHelper {
|
||||
buf.append("</select>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public int getShareBandwidth() {
|
||||
String irate = _context.getProperty(PROP_INBOUND_KBPS);
|
||||
String orate = _context.getProperty(PROP_OUTBOUND_KBPS);
|
||||
String pctStr = _context.getProperty(PROP_SHARE_PERCENTAGE);
|
||||
if ( (irate != null) && (orate != null) && (pctStr != null)) {
|
||||
try {
|
||||
int irateKBps = Integer.parseInt(irate);
|
||||
int orateKBps = Integer.parseInt(orate);
|
||||
if (irateKBps < 0 || orateKBps < 0)
|
||||
return 0;
|
||||
int pct = Integer.parseInt(pctStr);
|
||||
return (int) (((float) pct) * Math.min(irateKBps, orateKBps) / 100);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import net.i2p.stat.StatManager;
|
||||
public class ConfigStatsHandler extends FormHandler {
|
||||
private String _filename;
|
||||
private List _stats;
|
||||
private String _graphs;
|
||||
private boolean _explicitFilter;
|
||||
private String _explicitFilterValue;
|
||||
|
||||
@@ -48,6 +49,25 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
_log.debug("Updated stats: " + _stats);
|
||||
}
|
||||
|
||||
public void setGraphList(String stats[]) {
|
||||
if (stats != null) {
|
||||
String s = "";
|
||||
for (int i = 0; i < stats.length; i++) {
|
||||
String cur = stats[i].trim();
|
||||
if (cur.length() > 0) {
|
||||
if (s.length() > 0)
|
||||
s = s + ",";
|
||||
s = s + cur;
|
||||
}
|
||||
}
|
||||
_graphs = s;
|
||||
} else {
|
||||
_graphs = "";
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Updated graphs: " + _graphs);
|
||||
}
|
||||
|
||||
public void setExplicitFilter(String foo) { _explicitFilter = true; }
|
||||
public void setExplicitFilterValue(String filter) { _explicitFilterValue = filter; }
|
||||
|
||||
@@ -88,11 +108,13 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
}
|
||||
|
||||
_context.router().setConfigSetting(StatManager.PROP_STAT_FILTER, stats.toString());
|
||||
_context.router().setConfigSetting("stat.summaries", _graphs);
|
||||
boolean ok = _context.router().saveConfig();
|
||||
if (ok)
|
||||
addFormNotice("Stat filter and location updated successfully to: " + stats.toString());
|
||||
else
|
||||
addFormError("Failed to update the stat filter and location");
|
||||
addFormNotice("Graph list updated, may take up to 60s to be reflected here and on the <a href=\"graphs.jsp\">Graphs Page</a>");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.stat.FrequencyStat;
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -20,12 +21,15 @@ public class ConfigStatsHelper {
|
||||
/** list of names of stats which are remaining, ordered by nested groups */
|
||||
private List _stats;
|
||||
private String _currentStatName;
|
||||
private String _currentGraphName;
|
||||
private String _currentStatDescription;
|
||||
private String _currentGroup;
|
||||
/** true if the current stat is the first in the group */
|
||||
private boolean _currentIsFirstInGroup;
|
||||
/** true if the stat is being logged */
|
||||
private boolean _currentIsLogged;
|
||||
private boolean _currentIsGraphed;
|
||||
private boolean _currentCanBeGraphed;
|
||||
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
@@ -71,6 +75,7 @@ public class ConfigStatsHelper {
|
||||
public boolean hasMoreStats() {
|
||||
if (_stats.size() <= 0)
|
||||
return false;
|
||||
_currentIsGraphed = false;
|
||||
_currentStatName = (String)_stats.remove(0);
|
||||
RateStat rs = _context.statManager().getRate(_currentStatName);
|
||||
if (rs != null) {
|
||||
@@ -82,6 +87,16 @@ public class ConfigStatsHelper {
|
||||
else
|
||||
_currentIsFirstInGroup = false;
|
||||
_currentGroup = rs.getGroupName();
|
||||
long period = rs.getPeriods()[0]; // should be the minimum
|
||||
if (period <= 10*60*1000) {
|
||||
Rate r = rs.getRate(period);
|
||||
_currentCanBeGraphed = r != null;
|
||||
if (_currentCanBeGraphed)
|
||||
_currentIsGraphed = r.getSummaryListener() != null;
|
||||
_currentGraphName = _currentStatName + "." + period;
|
||||
} else {
|
||||
_currentCanBeGraphed = false;
|
||||
}
|
||||
} else {
|
||||
FrequencyStat fs = _context.statManager().getFrequency(_currentStatName);
|
||||
if (fs != null) {
|
||||
@@ -93,6 +108,7 @@ public class ConfigStatsHelper {
|
||||
else
|
||||
_currentIsFirstInGroup = false;
|
||||
_currentGroup = fs.getGroupName();
|
||||
_currentCanBeGraphed = false;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Stat does not exist?! [" + _currentStatName + "]");
|
||||
@@ -119,7 +135,10 @@ public class ConfigStatsHelper {
|
||||
/** What group is the current stat in */
|
||||
public String getCurrentGroupName() { return _currentGroup; }
|
||||
public String getCurrentStatName() { return _currentStatName; }
|
||||
public String getCurrentGraphName() { return _currentGraphName; }
|
||||
public String getCurrentStatDescription() { return _currentStatDescription; }
|
||||
public boolean getCurrentIsLogged() { return _currentIsLogged; }
|
||||
public boolean getCurrentIsGraphed() { return _currentIsGraphed; }
|
||||
public boolean getCurrentCanBeGraphed() { return _currentCanBeGraphed; }
|
||||
public String getExplicitFilter() { return _filter; }
|
||||
}
|
||||
|
@@ -55,20 +55,37 @@ public class GraphHelper {
|
||||
|
||||
public String getImages() {
|
||||
try {
|
||||
_out.write("<img src=\"viewstat.jsp?stat=bw.combined"
|
||||
+ "&periodCount=" + _periodCount
|
||||
+ "&width=" + _width
|
||||
+ "&height=" + _height
|
||||
+ "\" title=\"Combined bandwidth graph\" />\n");
|
||||
|
||||
List listeners = StatSummarizer.instance().getListeners();
|
||||
TreeSet ordered = new TreeSet(new AlphaComparator());
|
||||
ordered.addAll(listeners);
|
||||
|
||||
// go to some trouble to see if we have the data for the combined bw graph
|
||||
boolean hasTx = false;
|
||||
boolean hasRx = false;
|
||||
for (Iterator iter = ordered.iterator(); iter.hasNext(); ) {
|
||||
SummaryListener lsnr = (SummaryListener)iter.next();
|
||||
String title = lsnr.getRate().getRateStat().getName();
|
||||
if (title.equals("bw.sendRate")) hasTx = true;
|
||||
else if (title.equals("bw.recvRate")) hasRx = true;
|
||||
}
|
||||
|
||||
if (hasTx && hasRx && !_showEvents)
|
||||
_out.write("<img width=\""
|
||||
+ (_width + 83) + "\" height=\"" + (_height + 92)
|
||||
+ "\" src=\"viewstat.jsp?stat=bw.combined"
|
||||
+ "&periodCount=" + _periodCount
|
||||
+ "&width=" + _width
|
||||
+ "&height=" + (_height - 14)
|
||||
+ "\" title=\"Combined bandwidth graph\" />\n");
|
||||
|
||||
for (Iterator iter = ordered.iterator(); iter.hasNext(); ) {
|
||||
SummaryListener lsnr = (SummaryListener)iter.next();
|
||||
Rate r = lsnr.getRate();
|
||||
String title = r.getRateStat().getName() + " for " + DataHelper.formatDuration(_periodCount * r.getPeriod());
|
||||
_out.write("<img src=\"viewstat.jsp?stat=" + r.getRateStat().getName()
|
||||
_out.write("<img width=\""
|
||||
+ (_width + 83) + "\" height=\"" + (_height + 92)
|
||||
+ "\" src=\"viewstat.jsp?stat="
|
||||
+ r.getRateStat().getName()
|
||||
+ "&showEvents=" + _showEvents
|
||||
+ "&period=" + r.getPeriod()
|
||||
+ "&periodCount=" + _periodCount
|
||||
@@ -86,6 +103,7 @@ public class GraphHelper {
|
||||
}
|
||||
public String getForm() {
|
||||
try {
|
||||
_out.write("<p /><a href=\"configstats.jsp\">Select Stats to Graph</a><p />");
|
||||
_out.write("<form action=\"graphs.jsp\" method=\"GET\">");
|
||||
_out.write("Periods: <input size=\"3\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\" /><br />\n");
|
||||
_out.write("Plot averages: <input type=\"radio\" name=\"showEvents\" value=\"false\" " + (_showEvents ? "" : "checked=\"true\" ") + " /> ");
|
||||
@@ -119,4 +137,4 @@ class AlphaComparator implements Comparator {
|
||||
String rName = r.getRate().getRateStat().getName() + "." + r.getRate().getPeriod();
|
||||
return lName.compareTo(rName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package net.i2p.router.web;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.net.Socket;
|
||||
@@ -13,18 +12,51 @@ import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.EepGet;
|
||||
|
||||
/**
|
||||
* Handler to deal with reseed requests. This reseed from the URL
|
||||
* http://dev.i2p.net/i2pdb2/ unless the java env property "i2p.reseedURL" is
|
||||
* http://dev.i2p.net/i2pdb2/ unless the I2P configuration property "i2p.reseedURL" is
|
||||
* set. It always writes to ./netDb/, so don't mess with that.
|
||||
*
|
||||
*/
|
||||
public class ReseedHandler {
|
||||
private static ReseedRunner _reseedRunner;
|
||||
private RouterContext _context;
|
||||
private Log _log;
|
||||
|
||||
// Reject unreasonably big files, because we download into a ByteArrayOutputStream.
|
||||
private static final long MAX_RESEED_RESPONSE_SIZE = 8 * 1024 * 1024;
|
||||
|
||||
private static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb2/";
|
||||
|
||||
public ReseedHandler() {
|
||||
this(ContextHelper.getContext(null));
|
||||
}
|
||||
public ReseedHandler(RouterContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(ReseedHandler.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
* @param contextId begging few characters of the routerHash, or null to pick
|
||||
* the first one we come across.
|
||||
*/
|
||||
public void setContextId(String contextId) {
|
||||
try {
|
||||
_context = ContextHelper.getContext(contextId);
|
||||
_log = _context.logManager().getLog(ReseedHandler.class);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ReseedRunner _reseedRunner = new ReseedRunner();
|
||||
|
||||
public void setReseedNonce(String nonce) {
|
||||
if (nonce == null) return;
|
||||
if (nonce.equals(System.getProperty("net.i2p.router.web.ReseedHandler.nonce")) ||
|
||||
@@ -33,22 +65,28 @@ public class ReseedHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestReseed() {
|
||||
synchronized (_reseedRunner) {
|
||||
public void requestReseed() {
|
||||
synchronized (ReseedHandler.class) {
|
||||
if (_reseedRunner == null)
|
||||
_reseedRunner = new ReseedRunner();
|
||||
if (_reseedRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "true");
|
||||
System.out.println("Reseeding");
|
||||
I2PThread reseed = new I2PThread(_reseedRunner, "Reseed");
|
||||
reseed.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ReseedRunner implements Runnable {
|
||||
public class ReseedRunner implements Runnable, EepGet.StatusListener {
|
||||
private boolean _isRunning;
|
||||
public ReseedRunner() { _isRunning = false; }
|
||||
|
||||
public ReseedRunner() {
|
||||
_isRunning = false;
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding.");
|
||||
}
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
@@ -57,141 +95,148 @@ public class ReseedHandler {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb2/";
|
||||
/**
|
||||
* 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 static void reseed(boolean echoStatus) {
|
||||
String seedURL = I2PAppContext.getGlobalContext().getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
if ( (seedURL == null) || (seedURL.trim().length() <= 0) )
|
||||
seedURL = DEFAULT_SEED_URL;
|
||||
try {
|
||||
URL dir = new URL(seedURL);
|
||||
byte contentRaw[] = readURL(dir);
|
||||
if (contentRaw == null) return;
|
||||
String content = new String(contentRaw);
|
||||
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;
|
||||
}
|
||||
// EepGet status listeners
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
// Since readURL() runs an EepGet with 0 retries,
|
||||
// we can report errors with attemptFailed() instead of transferFailed().
|
||||
// It has the benefit of providing cause of failure, which helps resolve issues.
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("EepGet failed on " + url, cause);
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
// End of EepGet status listeners
|
||||
|
||||
int fetched = 0;
|
||||
int errors = 0;
|
||||
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
|
||||
try {
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
if (echoStatus) {
|
||||
System.out.print(".");
|
||||
if (fetched % 60 == 0)
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
/**
|
||||
* 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(boolean echoStatus) {
|
||||
|
||||
String seedURL = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
if ( (seedURL == null) || (seedURL.trim().length() <= 0) )
|
||||
seedURL = DEFAULT_SEED_URL;
|
||||
try {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage","");
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding: fetching seed URL.");
|
||||
URL dir = new URL(seedURL);
|
||||
byte contentRaw[] = readURL(dir);
|
||||
if (contentRaw == null) {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
|
||||
"Last reseed failed fully (failed reading seed URL). " +
|
||||
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
|
||||
"and if nothing helps, read FAQ about reseeding manually.");
|
||||
// Logging deprecated here since attemptFailed() provides better info
|
||||
_log.debug("Failed reading seed URL: " + seedURL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (echoStatus) System.out.println();
|
||||
} catch (Throwable t) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(ReseedHandler.class).error("Error reseeding", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void fetchSeed(String seedURL, String peer) throws Exception {
|
||||
URL url = new URL(seedURL + (seedURL.endsWith("/") ? "" : "/") + "routerInfo-" + peer + ".dat");
|
||||
String content = new String(contentRaw);
|
||||
Set urls = new HashSet();
|
||||
int cur = 0;
|
||||
while (true) {
|
||||
int start = content.indexOf("href=\"routerInfo-", cur);
|
||||
if (start < 0)
|
||||
break;
|
||||
|
||||
byte data[] = readURL(url);
|
||||
//System.out.println("read: " + (data != null ? data.length : -1));
|
||||
writeSeed(peer, data);
|
||||
}
|
||||
|
||||
private static byte[] readURL(URL url) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||
String hostname = url.getHost();
|
||||
int port = url.getPort();
|
||||
if (port < 0)
|
||||
port = 80;
|
||||
Socket s = new Socket(hostname, port);
|
||||
OutputStream out = s.getOutputStream();
|
||||
InputStream in = s.getInputStream();
|
||||
String request = getRequest(url);
|
||||
//System.out.println("Sending to " + hostname +":"+ port + ": " + request);
|
||||
out.write(request.getBytes());
|
||||
out.flush();
|
||||
// skip the HTTP response headers
|
||||
// (if we were smart, we'd check for HTTP 200, content-length, etc)
|
||||
int consecutiveNL = 0;
|
||||
while (true) {
|
||||
int cur = in.read();
|
||||
switch (cur) {
|
||||
case -1:
|
||||
return null;
|
||||
case '\n':
|
||||
case '\r':
|
||||
consecutiveNL++;
|
||||
break;
|
||||
default:
|
||||
consecutiveNL = 0;
|
||||
int end = content.indexOf(".dat\">", start);
|
||||
String name = content.substring(start+"href=\"routerInfo-".length(), end);
|
||||
urls.add(name);
|
||||
cur = end + 1;
|
||||
}
|
||||
if (urls.size() <= 0) {
|
||||
_log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
|
||||
"Last reseed failed fully (no routerInfo URLs at seed URL). " +
|
||||
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
|
||||
"and if nothing helps, read FAQ about reseeding manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
int fetched = 0;
|
||||
int errors = 0;
|
||||
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
|
||||
try {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage",
|
||||
"Reseeding: fetching router info from seed URL (" +
|
||||
fetched + " successful, " + errors + " errors, " + urls.size() + " total).");
|
||||
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
if (echoStatus) {
|
||||
System.out.print(".");
|
||||
if (fetched % 60 == 0)
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (echoStatus) System.out.println();
|
||||
if (errors > 0) {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
|
||||
"Last reseed failed partly (" + errors + " of " + urls.size() + "). " +
|
||||
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
|
||||
"and if nothing helps, read FAQ about reseeding manually.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
|
||||
"Last reseed failed fully (exception caught). " +
|
||||
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
|
||||
"and if nothing helps, read FAQ about reseeding manually.");
|
||||
_log.error("Error reseeding", t);
|
||||
}
|
||||
if (consecutiveNL == 4)
|
||||
break;
|
||||
}
|
||||
// ok, past the headers, grab the goods
|
||||
byte buf[] = new byte[1024];
|
||||
while (true) {
|
||||
int read = in.read(buf);
|
||||
if (read < 0)
|
||||
break;
|
||||
baos.write(buf, 0, read);
|
||||
|
||||
/* Since we don't return a value, we should always throw an exception if something fails. */
|
||||
private void fetchSeed(String seedURL, String peer) throws Exception {
|
||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(ReseedHandler.class);
|
||||
URL url = new URL(seedURL + (seedURL.endsWith("/") ? "" : "/") + "routerInfo-" + peer + ".dat");
|
||||
|
||||
byte data[] = readURL(url);
|
||||
if (data == null) {
|
||||
// Logging deprecated here since attemptFailed() provides better info
|
||||
_log.debug("Failed fetching seed: " + url.toString());
|
||||
throw new Exception ("Failed fetching seed.");
|
||||
}
|
||||
//System.out.println("read: " + (data != null ? data.length : -1));
|
||||
writeSeed(peer, data);
|
||||
}
|
||||
in.close();
|
||||
s.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private static String getRequest(URL url) {
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
String path = url.getPath();
|
||||
if ("".equals(path))
|
||||
path = "/";
|
||||
buf.append("GET ").append(path).append(" HTTP/1.0\n");
|
||||
buf.append("Host: ").append(url.getHost());
|
||||
int port = url.getPort();
|
||||
if ( (port > 0) && (port != 80) )
|
||||
buf.append(":").append(port);
|
||||
buf.append("\nConnection: close\n\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void writeSeed(String name, byte data[]) throws Exception {
|
||||
String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb");
|
||||
File netDbDir = new File(dirName);
|
||||
if (!netDbDir.exists()) {
|
||||
boolean ok = netDbDir.mkdirs();
|
||||
|
||||
private byte[] readURL(URL url) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||
|
||||
// Do a non-proxied eepget into our ByteArrayOutputStream with 0 retries
|
||||
EepGet get = new EepGet( I2PAppContext.getGlobalContext(), false, null, -1, 0, 0, MAX_RESEED_RESPONSE_SIZE,
|
||||
null, baos, url.toString(), false, null, null);
|
||||
get.addStatusListener(ReseedRunner.this);
|
||||
if (get.fetch()) return baos.toByteArray(); else return null;
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
|
||||
fos.write(data);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private void writeSeed(String name, byte data[]) throws Exception {
|
||||
String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb");
|
||||
File netDbDir = new File(dirName);
|
||||
if (!netDbDir.exists()) {
|
||||
boolean ok = netDbDir.mkdirs();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
|
||||
fos.write(data);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
if ( (args != null) && (args.length == 1) && (!Boolean.valueOf(args[0]).booleanValue()) ) {
|
||||
System.out.println("Not reseeding, as requested");
|
||||
return; // not reseeding on request
|
||||
}
|
||||
System.out.println("Reseeding");
|
||||
reseed(true);
|
||||
ReseedHandler reseedHandler = new ReseedHandler();
|
||||
reseedHandler.requestReseed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -88,7 +88,8 @@ public class RouterConsoleRunner {
|
||||
// get i2p started - they can reseed later in the web console)
|
||||
String names[] = (netDb.exists() ? netDb.list() : null);
|
||||
if ( (names == null) || (names.length < 15) ) {
|
||||
ReseedHandler.requestReseed();
|
||||
ReseedHandler reseedHandler = new ReseedHandler();
|
||||
reseedHandler.requestReseed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -45,27 +45,27 @@ public class StatSummarizer implements Runnable {
|
||||
|
||||
private static final String DEFAULT_DATABASES = "bw.sendRate.60000" +
|
||||
",bw.recvRate.60000" +
|
||||
",tunnel.testSuccessTime.60000" +
|
||||
",udp.outboundActiveCount.60000" +
|
||||
",udp.receivePacketSize.60000" +
|
||||
",udp.receivePacketSkew.60000" +
|
||||
",udp.sendConfirmTime.60000" +
|
||||
",udp.sendPacketSize.60000" +
|
||||
",router.activePeers.60000" +
|
||||
",router.activeSendPeers.60000" +
|
||||
",tunnel.acceptLoad.60000" +
|
||||
",tunnel.dropLoadProactive.60000" +
|
||||
",tunnel.buildExploratorySuccess.60000" +
|
||||
",tunnel.buildExploratoryReject.60000" +
|
||||
",tunnel.buildExploratoryExpire.60000" +
|
||||
",client.sendAckTime.60000" +
|
||||
",client.dispatchNoACK.60000" +
|
||||
",ntcp.sendTime.60000" +
|
||||
",ntcp.transmitTime.60000" +
|
||||
",ntcp.sendBacklogTime.60000" +
|
||||
",ntcp.receiveTime.60000" +
|
||||
",transport.sendMessageFailureLifetime.60000" +
|
||||
",transport.sendProcessingTime.60000";
|
||||
// ",tunnel.testSuccessTime.60000" +
|
||||
// ",udp.outboundActiveCount.60000" +
|
||||
// ",udp.receivePacketSize.60000" +
|
||||
// ",udp.receivePacketSkew.60000" +
|
||||
// ",udp.sendConfirmTime.60000" +
|
||||
// ",udp.sendPacketSize.60000" +
|
||||
",router.activePeers.60000";
|
||||
// ",router.activeSendPeers.60000" +
|
||||
// ",tunnel.acceptLoad.60000" +
|
||||
// ",tunnel.dropLoadProactive.60000" +
|
||||
// ",tunnel.buildExploratorySuccess.60000" +
|
||||
// ",tunnel.buildExploratoryReject.60000" +
|
||||
// ",tunnel.buildExploratoryExpire.60000" +
|
||||
// ",client.sendAckTime.60000" +
|
||||
// ",client.dispatchNoACK.60000" +
|
||||
// ",ntcp.sendTime.60000" +
|
||||
// ",ntcp.transmitTime.60000" +
|
||||
// ",ntcp.sendBacklogTime.60000" +
|
||||
// ",ntcp.receiveTime.60000" +
|
||||
// ",transport.sendMessageFailureLifetime.60000" +
|
||||
// ",transport.sendProcessingTime.60000";
|
||||
|
||||
private String adjustDatabases(String oldSpecs) {
|
||||
String spec = _context.getProperty("stat.summaries", DEFAULT_DATABASES);
|
||||
@@ -142,16 +142,17 @@ public class StatSummarizer implements Runnable {
|
||||
}
|
||||
|
||||
public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException {
|
||||
long end = _context.clock().now();
|
||||
long end = _context.clock().now() - 60*1000;
|
||||
if (periodCount <= 0) periodCount = SummaryListener.PERIODS;
|
||||
if (periodCount > SummaryListener.PERIODS)
|
||||
periodCount = SummaryListener.PERIODS;
|
||||
long period = 60*1000;
|
||||
long start = end - period*periodCount;
|
||||
long begin = System.currentTimeMillis();
|
||||
//long begin = System.currentTimeMillis();
|
||||
try {
|
||||
RrdGraphDef def = new RrdGraphDef();
|
||||
def.setTimePeriod(start/1000, end/1000);
|
||||
def.setTimePeriod(start/1000, 0);
|
||||
def.setBaseValue(1024);
|
||||
String title = "Bandwidth usage";
|
||||
if (!hideTitle)
|
||||
def.setTitle(title);
|
||||
@@ -159,15 +160,15 @@ public class StatSummarizer implements Runnable {
|
||||
String recvName = SummaryListener.createName(_context, "bw.recvRate.60000");
|
||||
def.datasource(sendName, sendName, sendName, "AVERAGE", "MEMORY");
|
||||
def.datasource(recvName, recvName, recvName, "AVERAGE", "MEMORY");
|
||||
def.area(sendName, Color.BLUE, "Outbound bytes/second");
|
||||
//def.line(sendName, Color.BLUE, "Outbound bytes/second", 3);
|
||||
//def.line(recvName, Color.RED, "Inbound bytes/second@r", 3);
|
||||
def.area(recvName, Color.RED, "Inbound bytes/second@r");
|
||||
def.area(sendName, Color.BLUE, "Outbound bytes/sec");
|
||||
//def.line(sendName, Color.BLUE, "Outbound bytes/sec", 3);
|
||||
def.line(recvName, Color.RED, "Inbound bytes/sec@r", 3);
|
||||
//def.area(recvName, Color.RED, "Inbound bytes/sec@r");
|
||||
if (!hideLegend) {
|
||||
def.gprint(sendName, "AVERAGE", "outbound average: @2@sbytes/second");
|
||||
def.gprint(sendName, "MAX", " max: @2@sbytes/second@r");
|
||||
def.gprint(recvName, "AVERAGE", "inbound average: @2bytes/second@s");
|
||||
def.gprint(recvName, "MAX", " max: @2@sbytes/second@r");
|
||||
def.gprint(sendName, "AVERAGE", "out average: @2@sbytes/sec");
|
||||
def.gprint(sendName, "MAX", " max: @2@sbytes/sec@r");
|
||||
def.gprint(recvName, "AVERAGE", "in average: @2@sbytes/sec");
|
||||
def.gprint(recvName, "MAX", " max: @2@sbytes/sec@r");
|
||||
}
|
||||
if (!showCredit)
|
||||
def.setShowSignature(false);
|
||||
@@ -188,7 +189,7 @@ public class StatSummarizer implements Runnable {
|
||||
data = graph.getPNGBytes();
|
||||
else
|
||||
data = graph.getPNGBytes(width, height);
|
||||
long timeToPlot = System.currentTimeMillis() - begin;
|
||||
//long timeToPlot = System.currentTimeMillis() - begin;
|
||||
out.write(data);
|
||||
//File t = File.createTempFile("jrobinData", ".xml");
|
||||
//_listener.getData().dumpXml(new FileOutputStream(t));
|
||||
@@ -201,6 +202,9 @@ public class StatSummarizer implements Runnable {
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error rendering", ioe);
|
||||
throw ioe;
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_log.error("Error rendering", oom);
|
||||
throw new IOException("Error plotting: " + oom.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -154,7 +154,7 @@ class SummaryRenderer {
|
||||
*
|
||||
*/
|
||||
public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException {
|
||||
long end = ctx.clock().now();
|
||||
long end = ctx.clock().now() - 60*1000;
|
||||
long start = end - 60*1000*SummaryListener.PERIODS;
|
||||
long begin = System.currentTimeMillis();
|
||||
try {
|
||||
@@ -174,17 +174,26 @@ class SummaryRenderer {
|
||||
}
|
||||
public void render(OutputStream out) throws IOException { render(out, -1, -1, false, false, false, false, -1, true); }
|
||||
public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException {
|
||||
long end = _listener.now();
|
||||
long end = _listener.now() - 60*1000;
|
||||
if (periodCount <= 0) periodCount = SummaryListener.PERIODS;
|
||||
if (periodCount > SummaryListener.PERIODS)
|
||||
periodCount = SummaryListener.PERIODS;
|
||||
long start = end - _listener.getRate().getPeriod()*periodCount;
|
||||
long begin = System.currentTimeMillis();
|
||||
//long begin = System.currentTimeMillis();
|
||||
try {
|
||||
RrdGraphDef def = new RrdGraphDef();
|
||||
def.setTimePeriod(start/1000, end/1000);
|
||||
String title = _listener.getRate().getRateStat().getName() + " averaged for "
|
||||
+ DataHelper.formatDuration(_listener.getRate().getPeriod());
|
||||
def.setTimePeriod(start/1000, 0);
|
||||
String name = _listener.getRate().getRateStat().getName();
|
||||
// heuristic to set K=1024
|
||||
if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0)
|
||||
&& !showEvents)
|
||||
def.setBaseValue(1024);
|
||||
String title = name;
|
||||
if (showEvents)
|
||||
title = title + " events in ";
|
||||
else
|
||||
title = title + " averaged for ";
|
||||
title = title + DataHelper.formatDuration(_listener.getRate().getPeriod());
|
||||
if (!hideTitle)
|
||||
def.setTitle(title);
|
||||
String path = _listener.getData().getPath();
|
||||
@@ -203,8 +212,9 @@ class SummaryRenderer {
|
||||
def.datasource(plotName, path, plotName, "AVERAGE", "MEMORY");
|
||||
def.area(plotName, Color.BLUE, descr + "@r");
|
||||
if (!hideLegend) {
|
||||
def.gprint(plotName, "AVERAGE", "average: @2@s");
|
||||
def.gprint(plotName, "MAX", " max: @2@s@r");
|
||||
def.gprint(plotName, "AVERAGE", "avg: @2@s");
|
||||
def.gprint(plotName, "MAX", " max: @2@s");
|
||||
def.gprint(plotName, "LAST", " now: @2@s@r");
|
||||
}
|
||||
if (!showCredit)
|
||||
def.setShowSignature(false);
|
||||
@@ -233,7 +243,7 @@ class SummaryRenderer {
|
||||
data = graph.getPNGBytes();
|
||||
else
|
||||
data = graph.getPNGBytes(width, height);
|
||||
long timeToPlot = System.currentTimeMillis() - begin;
|
||||
//long timeToPlot = System.currentTimeMillis() - begin;
|
||||
out.write(data);
|
||||
//File t = File.createTempFile("jrobinData", ".xml");
|
||||
//_listener.getData().dumpXml(new FileOutputStream(t));
|
||||
@@ -245,6 +255,9 @@ class SummaryRenderer {
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error rendering", ioe);
|
||||
throw ioe;
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_log.error("Error rendering", oom);
|
||||
throw new IOException("Error plotting: " + oom.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,9 +43,21 @@
|
||||
A negative rate means a default limit of 16KBytes per second.</i><br />
|
||||
Bandwidth share percentage:
|
||||
<jsp:getProperty name="nethelper" property="sharePercentageBox" /><br />
|
||||
Sharing a higher percentage will improve your anonymity and help the network<br />
|
||||
<% int share = nethelper.getShareBandwidth();
|
||||
if (share < 12) {
|
||||
out.print("<b>NOTE</b>: You have configured I2P to share only " + share + "KBps. ");
|
||||
out.print("I2P requires at least 12KBps to enable sharing. ");
|
||||
out.print("Please enable sharing (participating in tunnels) by configuring more bandwidth. ");
|
||||
out.print("It improves your anonymity by creating cover traffic, and helps the network.<br />");
|
||||
} else {
|
||||
out.print("You have configured I2P to share " + share + "KBps. ");
|
||||
out.print("The higher the share bandwidth the more you improve your anonymity and help the network.<br />");
|
||||
}
|
||||
%>
|
||||
<p>
|
||||
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
|
||||
<hr />
|
||||
<!--
|
||||
<b>Enable load testing: </b>
|
||||
<input type="checkbox" name="enableloadtesting" value="true" <jsp:getProperty name="nethelper" property="enableLoadTesting" /> />
|
||||
<p>If enabled, your router will periodically anonymously probe some of your peers
|
||||
@@ -54,6 +66,7 @@
|
||||
load testing is fed into the profiles as well as the
|
||||
<a href="oldstats.jsp#test.rtt">test.rtt</a> and related stats.</p>
|
||||
<hr />
|
||||
-->
|
||||
<b>External UDP address:</b> <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
|
||||
<b>Require SSU introductions? </b>
|
||||
<input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
|
||||
@@ -70,14 +83,21 @@
|
||||
Externally reachable hostname or IP address:
|
||||
<input name ="ntcphost" type="text" size="16" value="<jsp:getProperty name="nethelper" property="ntcphostname" />" />
|
||||
(dyndns and the like are fine)<br />
|
||||
OR use IP address detected by SSU
|
||||
(currently <jsp:getProperty name="nethelper" property="udpIP" />)?
|
||||
<input type="checkbox" name="ntcpAutoIP" value="true" <jsp:getProperty name="nethelper" property="tcpAutoIPChecked" /> /><br />
|
||||
<p>
|
||||
Externally reachable TCP port:
|
||||
<input name ="ntcpport" type="text" size="6" value="<jsp:getProperty name="nethelper" property="ntcpport" />" /><br />
|
||||
OR use the same port configured for SSU
|
||||
(currently <jsp:getProperty name="nethelper" property="udpPort" />)?
|
||||
<input type="checkbox" name="ntcpAutoPort" value="true" <jsp:getProperty name="nethelper" property="tcpAutoPortChecked" /> /><br />
|
||||
<p>You do <i>not</i> need to allow inbound TCP connections - outbound connections work with no
|
||||
configuration. However, if you want to receive inbound TCP connections, you <b>must</b> poke a hole
|
||||
in your NAT or firewall for unsolicited TCP connections. If you specify the wrong IP address or
|
||||
hostname, or do not properly configure your NAT or firewall, your network performance will degrade
|
||||
substantially. When in doubt, leave the hostname and port number blank.</p>
|
||||
<p><b>Note: changing this setting will terminate all of your connections and effectively
|
||||
<p><b>Note: changing any of these settings will terminate all of your connections and effectively
|
||||
restart your router.</b>
|
||||
<hr />
|
||||
<!--
|
||||
|
@@ -78,22 +78,26 @@ function toggleAll(category)
|
||||
<table>
|
||||
<% while (statshelper.hasMoreStats()) {
|
||||
while (statshelper.groupRequired()) { %>
|
||||
<tr><td valign="top" align="left" colspan="2">
|
||||
<tr><td valign="top" align="left" colspan="3">
|
||||
<b><%=statshelper.getCurrentGroupName()%></b>
|
||||
(<a href="javascript: void(null);" onclick="toggleAll('<%=statshelper.getCurrentGroupName()%>')">toggle all</a>)
|
||||
</td></tr><%
|
||||
</td></tr><tr><td>Log</td><td>Graph</td><td></td></tr><%
|
||||
} // end iterating over required groups for the current stat %>
|
||||
<tr><td valign="top" align="left">
|
||||
<input id="<%=statshelper.getCurrentGroupName()%>" type="checkbox" name="statList" value="<%=statshelper.getCurrentStatName()%>" <%
|
||||
if (statshelper.getCurrentIsLogged()) { %>checked="true" <% } %>/></td>
|
||||
<td valign="top" align="left">
|
||||
<% if (statshelper.getCurrentCanBeGraphed()) { %>
|
||||
<input id="<%=statshelper.getCurrentGroupName()%>" type="checkbox" name="graphList" value="<%=statshelper.getCurrentGraphName()%>" <%
|
||||
if (statshelper.getCurrentIsGraphed()) { %>checked="true" <% } %>/><% } %></td>
|
||||
<td valign="top" align="left"><b><%=statshelper.getCurrentStatName()%>:</b><br />
|
||||
<%=statshelper.getCurrentStatDescription()%></td></tr><%
|
||||
} // end iterating over all stats %>
|
||||
<tr><td colspan="2"><hr /></td></tr>
|
||||
<tr><td colspan="3"><hr /></td></tr>
|
||||
<tr><td><input type="checkbox" name="explicitFilter" /></td>
|
||||
<td>Advanced filter:
|
||||
<td colspan="2">Advanced filter:
|
||||
<input type="text" name="explicitFilterValue" value="<%=statshelper.getExplicitFilter()%>" size="40" /></td></tr>
|
||||
<tr><td colspan="2"><hr /></td></tr>
|
||||
<tr><td colspan="3"><hr /></td></tr>
|
||||
<tr><td><input type="submit" name="shouldsave" value="Save changes" /> </td>
|
||||
<td><input type="reset" value="Cancel" /></td></tr>
|
||||
</form>
|
||||
@@ -101,4 +105,4 @@ function toggleAll(category)
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@@ -5,6 +5,7 @@
|
||||
<html><head>
|
||||
<title>I2P Router Console - home</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
</head><body>
|
||||
<%
|
||||
if (System.getProperty("router.consoleNonce") == null) {
|
||||
|
@@ -24,7 +24,7 @@
|
||||
<!-- Could not find docs/toolbar.html! -->
|
||||
<a href="susimail/susimail">Susimail</a> |
|
||||
<a href="susidns/index.jsp">SusiDNS</a> |
|
||||
<a href="syndie/">Syndie</a> |
|
||||
<!-- <a href="syndie/">Syndie</a> | -->
|
||||
<a href="i2psnark/">I2PSnark</a> |
|
||||
<a href="http://localhost:7658/">My Eepsite</a> <br>
|
||||
<a href="i2ptunnel/index.jsp">I2PTunnel</a> |
|
||||
|
@@ -43,13 +43,16 @@
|
||||
<b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
|
||||
<!-- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br /> -->
|
||||
<b>Known:</b> <jsp:getProperty name="helper" property="allPeers" /><br /><%
|
||||
if (helper.getActivePeers() <= 0) {
|
||||
if (helper.getActivePeers() <= 0) {
|
||||
%><b><a href="config.jsp">check your NAT/firewall</a></b><br /><%
|
||||
}
|
||||
}
|
||||
// If showing the reseed link is allowed
|
||||
if (helper.allowReseed()) {
|
||||
if ("true".equals(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false"))) {
|
||||
out.print(" <i>reseeding</i>");
|
||||
// While reseed occurring, show status message instead
|
||||
out.print("<i>" + System.getProperty("net.i2p.router.web.ReseedHandler.statusMessage","") + "</i><br />");
|
||||
} else {
|
||||
// While no reseed occurring, show reseed link
|
||||
long nonce = new java.util.Random().nextLong();
|
||||
String prev = System.getProperty("net.i2p.router.web.ReseedHandler.nonce");
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.ReseedHandler.noncePrev", prev);
|
||||
@@ -59,7 +62,14 @@
|
||||
uri = uri + "&reseedNonce=" + nonce;
|
||||
else
|
||||
uri = uri + "?reseedNonce=" + nonce;
|
||||
out.print(" <a href=\"" + uri + "\">reseed</a>");
|
||||
out.print(" <a href=\"" + uri + "\">reseed</a><br />");
|
||||
}
|
||||
}
|
||||
// If a new reseed ain't running, and the last reseed had errors, show error message
|
||||
if ("false".equals(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false"))) {
|
||||
String reseedErrorMessage = System.getProperty("net.i2p.router.web.ReseedHandler.errorMessage","");
|
||||
if (reseedErrorMessage.length() > 0) {
|
||||
out.print("<i>" + reseedErrorMessage + "</i><br />");
|
||||
}
|
||||
}
|
||||
%><hr />
|
||||
|
@@ -29,9 +29,15 @@ public class I2PSocketFull implements I2PSocket {
|
||||
if (c == null) return;
|
||||
if (c.getIsConnected()) {
|
||||
OutputStream out = c.getOutputStream();
|
||||
if (out != null)
|
||||
out.close();
|
||||
c.disconnect(true);
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignore any write error, as we want to keep on and kill the
|
||||
// con (thanks Complication!)
|
||||
}
|
||||
}
|
||||
c.disconnect(true);
|
||||
} else {
|
||||
//throw new IOException("Not connected");
|
||||
}
|
||||
|
14
build.xml
14
build.xml
@@ -30,7 +30,7 @@
|
||||
<ant dir="apps/addressbook/" target="war" />
|
||||
<ant dir="apps/susimail/" target="war" />
|
||||
<ant dir="apps/susidns/src" target="all" />
|
||||
<ant dir="apps/syndie/java/" target="jar" />
|
||||
<!-- <ant dir="apps/syndie/java/" target="jar" /> -->
|
||||
<ant dir="apps/i2psnark/java/" target="standalone" />
|
||||
</target>
|
||||
<target name="buildrouter">
|
||||
@@ -103,9 +103,11 @@
|
||||
<copy file="apps/addressbook/dist/addressbook.war" todir="build/" />
|
||||
<copy file="apps/susimail/susimail.war" todir="build/" />
|
||||
<copy file="apps/susidns/src/susidns.war" todir="build/" />
|
||||
<!--
|
||||
<copy file="apps/syndie/syndie.war" todir="build/" />
|
||||
<copy file="apps/syndie/java/build/syndie.jar" todir="build/" />
|
||||
<copy file="apps/syndie/java/build/sucker.jar" todir="build/" />
|
||||
-->
|
||||
<copy file="apps/i2psnark/i2psnark.war" todir="build/" />
|
||||
<copy file="apps/i2psnark/java/build/i2psnark.jar" todir="build/" />
|
||||
<copy file="apps/jdom/jdom.jar" todir="build/" />
|
||||
@@ -195,7 +197,7 @@
|
||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="build/systray.jar" todir="pkg-temp/lib" />
|
||||
<copy file="build/sucker.jar" todir="pkg-temp/lib" />
|
||||
<!-- <copy file="build/sucker.jar" todir="pkg-temp/lib" /> -->
|
||||
<copy file="build/i2psnark.jar" todir="pkg-temp/lib/" />
|
||||
<copy file="i2p.exe" todir="pkg-temp/" failonerror="false" />
|
||||
<copy file="installer/resources/runplain.sh" todir="pkg-temp/" />
|
||||
@@ -209,7 +211,7 @@
|
||||
<copy file="build/addressbook.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/susimail.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/susidns.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/syndie.war" todir="pkg-temp/webapps/" />
|
||||
<!-- <copy file="build/syndie.war" todir="pkg-temp/webapps/" /> -->
|
||||
<copy file="build/i2psnark.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="apps/i2psnark/java/build/launch-i2psnark.jar" todir="pkg-temp/" />
|
||||
<copy file="apps/i2psnark/jetty-i2psnark.xml" todir="pkg-temp/" />
|
||||
@@ -279,11 +281,13 @@
|
||||
<copy file="installer/resources/eepsite_index.html" tofile="pkg-temp/eepsite/docroot/index.html" />
|
||||
<copy file="installer/resources/favicon.ico" tofile="pkg-temp/eepsite/docroot/favicon.ico" />
|
||||
<copy file="installer/resources/jetty.xml" tofile="pkg-temp/eepsite/jetty.xml" />
|
||||
<!--
|
||||
<mkdir dir="pkg-temp/syndie" />
|
||||
<mkdir dir="pkg-temp/syndie/archive" />
|
||||
<mkdir dir="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=" />
|
||||
<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="tarball" depends="preppkg">
|
||||
<tar compression="bzip2" destfile="i2p.tar.bz2">
|
||||
@@ -320,7 +324,7 @@
|
||||
<copy file="build/addressbook.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/susimail.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/susidns.war" todir="pkg-temp/webapps/" />
|
||||
<copy file="build/syndie.war" todir="pkg-temp/webapps/" />
|
||||
<!-- <copy file="build/syndie.war" todir="pkg-temp/webapps/" /> -->
|
||||
<copy file="build/i2psnark.war" todir="pkg-temp/webapps/" />
|
||||
<!-- <copy file="apps/i2psnark/java/build/launch-i2psnark.jar" todir="pkg-temp/" /> -->
|
||||
<copy file="apps/i2psnark/jetty-i2psnark.xml" todir="pkg-temp/" />
|
||||
@@ -351,11 +355,13 @@
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
||||
<mkdir dir="pkg-temp/eepsite/cgi-bin" />
|
||||
<!--
|
||||
<mkdir dir="pkg-temp/syndie" />
|
||||
<mkdir dir="pkg-temp/syndie/archive" />
|
||||
<mkdir dir="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=" />
|
||||
<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/" />
|
||||
|
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
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 final static String ID = "$Revision: 1.71 $ $Date: 2007-03-17 16:19:10 $";
|
||||
public final static String VERSION = "0.6.1.29";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
@@ -184,6 +184,7 @@ public class Rate {
|
||||
private static final int SLACK = 2000;
|
||||
public void coalesce() {
|
||||
long now = now();
|
||||
double correctedTotalValue; // for summaryListener which divides by rounded EventCount
|
||||
synchronized (_lock) {
|
||||
long measuredPeriod = now - _lastCoalesceDate;
|
||||
if (measuredPeriod < _period - SLACK) {
|
||||
@@ -198,9 +199,14 @@ public class Rate {
|
||||
// how much were we off by? (so that we can sample down the measured values)
|
||||
double periodFactor = measuredPeriod / (double)_period;
|
||||
_lastTotalValue = _currentTotalValue / periodFactor;
|
||||
_lastEventCount = (long) ( (_currentEventCount + periodFactor - 1) / periodFactor);
|
||||
_lastEventCount = (long) (0.499999 + (_currentEventCount / periodFactor));
|
||||
_lastTotalEventTime = (long) (_currentTotalEventTime / periodFactor);
|
||||
_lastCoalesceDate = now;
|
||||
if (_currentEventCount == 0)
|
||||
correctedTotalValue = 0;
|
||||
else
|
||||
correctedTotalValue = _currentTotalValue *
|
||||
(_lastEventCount / (double) _currentEventCount);
|
||||
|
||||
if (_lastTotalValue > _extremeTotalValue) {
|
||||
_extremeTotalValue = _lastTotalValue;
|
||||
@@ -213,7 +219,7 @@ public class Rate {
|
||||
_currentTotalEventTime = 0;
|
||||
}
|
||||
if (_summaryListener != null)
|
||||
_summaryListener.add(_lastTotalValue, _lastEventCount, _lastTotalEventTime, _period);
|
||||
_summaryListener.add(correctedTotalValue, _lastEventCount, _lastTotalEventTime, _period);
|
||||
}
|
||||
|
||||
public void setSummaryListener(RateSummaryListener listener) { _summaryListener = listener; }
|
||||
|
@@ -33,7 +33,10 @@ public class EepGet {
|
||||
private String _proxyHost;
|
||||
private int _proxyPort;
|
||||
private int _numRetries;
|
||||
private long _minSize; // minimum and maximum acceptable response size, -1 signifies unlimited,
|
||||
private long _maxSize; // applied both against whole responses and chunks
|
||||
private String _outputFile;
|
||||
private OutputStream _outputStream;
|
||||
private String _url;
|
||||
private String _postData;
|
||||
private boolean _allowCaching;
|
||||
@@ -53,35 +56,48 @@ public class EepGet {
|
||||
private boolean _notModified;
|
||||
private String _contentType;
|
||||
|
||||
// Constructor 7, calls 3 with: do proxy
|
||||
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
||||
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url);
|
||||
}
|
||||
// Constructor 6, calls 1 with: do proxy, no etag
|
||||
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching) {
|
||||
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url, allowCaching, null);
|
||||
}
|
||||
// Constructor 5, calls 3 with: no proxy
|
||||
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url) {
|
||||
this(ctx, false, null, -1, numRetries, outputFile, url);
|
||||
}
|
||||
// Constructor 4, calls 1 with: no proxy, no etag
|
||||
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url, boolean allowCaching) {
|
||||
this(ctx, false, null, -1, numRetries, outputFile, url, allowCaching, null);
|
||||
}
|
||||
// Constructor 3, calls 1 with: do caching, no etag
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, true, null);
|
||||
}
|
||||
// Constructor 2, calls 0 with: no output buffer, do caching, no etag
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, String postData) {
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, true, null, postData);
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, true, null, postData);
|
||||
}
|
||||
// Constructor 1, calls 0 with: no output buffer, no postdata
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag) {
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, allowCaching, etag, null);
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, null);
|
||||
}
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag, String postData) {
|
||||
// Constructor 0, real constructor
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize,
|
||||
String outputFile, OutputStream outputStream, String url, boolean allowCaching,
|
||||
String etag, String postData) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(EepGet.class);
|
||||
_shouldProxy = shouldProxy;
|
||||
_proxyHost = proxyHost;
|
||||
_proxyPort = proxyPort;
|
||||
_numRetries = numRetries;
|
||||
_outputFile = outputFile;
|
||||
_minSize = minSize;
|
||||
_maxSize = maxSize;
|
||||
_outputFile = outputFile; // if outputFile is set, outputStream must be null
|
||||
_outputStream = outputStream; // if both are set, outputStream overrides outputFile
|
||||
_url = url;
|
||||
_postData = postData;
|
||||
_alreadyTransferred = 0;
|
||||
@@ -352,14 +368,20 @@ public class EepGet {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** return true if the URL was completely retrieved */
|
||||
/** a single fetch attempt */
|
||||
private void doFetch() throws IOException {
|
||||
readHeaders();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Headers read completely, reading " + _bytesRemaining);
|
||||
|
||||
boolean strictSize = (_bytesRemaining >= 0);
|
||||
|
||||
|
||||
// If minimum or maximum size defined, ensure they aren't exceeded
|
||||
if ((_minSize > -1) && (_bytesRemaining < _minSize))
|
||||
throw new IOException("HTTP response size " + _bytesRemaining + " violates minimum of " + _minSize + " bytes");
|
||||
if ((_maxSize > -1) && (_bytesRemaining > _maxSize))
|
||||
throw new IOException("HTTP response size " + _bytesRemaining + " violates maximum of " + _maxSize + " bytes");
|
||||
|
||||
int remaining = (int)_bytesRemaining;
|
||||
byte buf[] = new byte[1024];
|
||||
while (_keepFetching && ( (remaining > 0) || !strictSize )) {
|
||||
@@ -371,6 +393,11 @@ public class EepGet {
|
||||
break;
|
||||
_out.write(buf, 0, read);
|
||||
_bytesTransferred += read;
|
||||
// This seems necessary to properly resume a partial download into a stream,
|
||||
// as nothing else increments _alreadyTransferred, and there's no file length to check.
|
||||
// Hopefully this won't break compatibility with existing status listeners
|
||||
// (cause them to behave weird, or show weird numbers).
|
||||
_alreadyTransferred += read;
|
||||
remaining -= read;
|
||||
if (remaining==0 && _encodingChunked) {
|
||||
if(_proxyIn.read()=='\r' && _proxyIn.read()=='\n') {
|
||||
@@ -419,12 +446,14 @@ public class EepGet {
|
||||
boolean rcOk = false;
|
||||
switch (responseCode) {
|
||||
case 200: // full
|
||||
_out = new FileOutputStream(_outputFile, false);
|
||||
if (_outputStream != null) _out = _outputStream;
|
||||
else _out = new FileOutputStream(_outputFile, false);
|
||||
_alreadyTransferred = 0;
|
||||
rcOk = true;
|
||||
break;
|
||||
case 206: // partial
|
||||
_out = new FileOutputStream(_outputFile, true);
|
||||
if (_outputStream != null) _out = _outputStream;
|
||||
else _out = new FileOutputStream(_outputFile, true);
|
||||
rcOk = true;
|
||||
break;
|
||||
case 304: // not modified
|
||||
@@ -588,9 +617,16 @@ public class EepGet {
|
||||
private boolean isNL(byte b) { return (b == NL); }
|
||||
|
||||
private void sendRequest() throws IOException {
|
||||
File outFile = new File(_outputFile);
|
||||
if (outFile.exists())
|
||||
_alreadyTransferred = outFile.length();
|
||||
if (_outputStream != null) {
|
||||
// We are reading into a stream supplied by a caller,
|
||||
// for which we cannot easily determine how much we've written.
|
||||
// Assume that _alreadyTransferred holds the right value
|
||||
// (we should never be restarted to work on an old stream).
|
||||
} else {
|
||||
File outFile = new File(_outputFile);
|
||||
if (outFile.exists())
|
||||
_alreadyTransferred = outFile.length();
|
||||
}
|
||||
|
||||
String req = getRequest();
|
||||
|
||||
|
114
history.txt
114
history.txt
@@ -1,4 +1,116 @@
|
||||
$Id: history.txt,v 1.561 2007-03-17 16:18:12 jrandom Exp $
|
||||
$Id: history.txt,v 1.583 2007-08-13 14:42:59 zzz Exp $
|
||||
|
||||
* 2007-08-23 0.6.1.29 released
|
||||
|
||||
2007-08-12 zzz
|
||||
* readme.html - Add inproxy.tino.i2p, replace search.i2p with eepsites.i2p,
|
||||
tweak the eepsite and troubleshooting sections
|
||||
|
||||
2007-08-11 zzz
|
||||
* Add stats for individual tunnel rates (nice when graphed)
|
||||
* i2psnark: Fix outbound tunnel nickname
|
||||
|
||||
2007-08-05 Complication
|
||||
* Update the sharing calculator on config.jsp
|
||||
and explain the trade-off even more thoroughly.
|
||||
|
||||
2007-08-04 Complication
|
||||
* Lower the threshold between the K and L bandwidth class,
|
||||
so that K is now < 12 KB/s, instead of <= 16 KB/s.
|
||||
Hopefully this lets people with 128 kbit/s (16 KB/s) upload lines
|
||||
participate in routing, if they keep the default share percentage.
|
||||
|
||||
2007-07-16 zzz
|
||||
* i2psnark: Add tooltip info for choked/uninterested
|
||||
|
||||
2007-07-16 zzz
|
||||
* Make selection of graphed data configurable via configstats.jsp,
|
||||
remove most of the default graphs to save some memory
|
||||
|
||||
2007-07-15 zzz
|
||||
* Add current values to graph legends
|
||||
* Fix up previous Rate fix to check for divide by zero
|
||||
|
||||
2007-07-14 Complication
|
||||
* Take the post-download routerInfo size check back out of ReseedHandler,
|
||||
since it wasn't helpful, and a lower limit caused false warnings.
|
||||
* Give EepGet ability to enforce a min/max HTTP response size.
|
||||
* Enforce a maximum response size of 8 MB when ReseedHandler
|
||||
downloads into a ByteArrayOutputStream.
|
||||
* Refactor ReseedHandler/ReseedRunner from static to ordinary classes,
|
||||
change invocation from RouterConsoleRunner accordingly.
|
||||
* Add an EepGet status listener to ReseedHandler to log causes of reseed failure,
|
||||
provide status reports to indicate the progress of reseeding.
|
||||
* Enable icon for default eepsite, and the index page
|
||||
of the router console (more later).
|
||||
|
||||
2007-07-14 zzz
|
||||
* Clean up graphs.jsp - set K=1024 where appropriate,
|
||||
output image sizes in html, catch ooms, other minor tweaks
|
||||
* Fix current event count truncation which fixes graphs with low
|
||||
60-sec event counts displaying high values
|
||||
(bw.* and router.* graphs for example were 1.5x too high)
|
||||
Affects all "events per period" (non-lifetime) counts.
|
||||
|
||||
2007-07-09 zzz
|
||||
* i2psnark: give a better error message for a non-i2p torrent
|
||||
|
||||
2007-07-07 zzz
|
||||
* Add auto-detect IP/Port to NTCP. When enabled on config.jsp,
|
||||
SSU will notify/restart NTCP when the external address changes.
|
||||
Now you can enable inbound TCP without a static IP or dyndns service.
|
||||
|
||||
2007-07-04 zzz
|
||||
* Display calculated share bandwidth and remove load testing
|
||||
on config.jsp
|
||||
|
||||
2007-07-01 zzz
|
||||
* Replace broken option i2np.udp.alwaysPreferred with
|
||||
i2np.udp.preferred and adjust UDP bids; possible settings are
|
||||
"false" (default), "true", and "always".
|
||||
Default setting results in same behavior as before
|
||||
(NTCP is preferred unless it isn't established and UDP is established).
|
||||
Use to compare NTCP and UDP transports.
|
||||
|
||||
2007-06-27 jrandom
|
||||
* fix for a streaming lib bug that could leave a thread waiting
|
||||
indefinitely (thanks Complication!)
|
||||
|
||||
2007-06-16 Complication
|
||||
* First pass on EepGet and ReseedHandler improvements,
|
||||
please avoid use on routers which matter!
|
||||
* Give EepGet ability of downloading into an OutputStream,
|
||||
such as the ByteArrayOutputStream of ReseedHandler.
|
||||
* Detect failure to reseed better, report it persistently
|
||||
and more verbosely, provide a link to logs
|
||||
and suggest manual reseed.
|
||||
|
||||
2007-05-06 Complication
|
||||
* Fix the build.xml file, so the preppkg build target won't try copying files
|
||||
which became deprecated with the old Syndie (thanks for alerting, itsu!)
|
||||
|
||||
2007-03-31 zzz
|
||||
* Add trevorreznik jump server to the http proxy error page
|
||||
* Add anonymity to the trackers supporting details links in i2psnark
|
||||
|
||||
2007-03-24 zzz
|
||||
* Remove Syndie from build targets and navbar
|
||||
|
||||
2007-03-22 zzz
|
||||
* i2psnark tracker handling tweaks:
|
||||
- Add link to tracker details page (Postman only for now, requires bytemonsoon patch)
|
||||
- Add Base URL to tracker list configuration
|
||||
- Web page links built from tracker list Base URLs
|
||||
- Only build and sort tracker list once
|
||||
- Add anonymityWeb tracker to default list
|
||||
- Add tooltip info for TrackerErrs
|
||||
- Stop torrent if not registered with tracker
|
||||
- Mark temp files as delete on exit
|
||||
|
||||
2007-03-18 zzz
|
||||
* i2psnark: Cleanup some handling of saved partial pieces
|
||||
* i2psnark: Put bit counting in Bitfield.java for efficiency
|
||||
* i2psnark: Save torrent completion state in i2psnark.config
|
||||
|
||||
* 2007-03-17 0.6.1.28 released
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2007-02-15 18:25:04 $">
|
||||
<i2p.release version="0.6.1.28" date="2007/02/15" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2007-03-17 20:47:59 $">
|
||||
<i2p.release version="0.6.1.29" 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.28</appversion>
|
||||
<appversion>0.6.1.29</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
</authors>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to your eepsite</title>
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to your eepsite</h1>
|
||||
|
30
news.xml
30
news.xml
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2007-03-15 03:21:35 $">
|
||||
<i2p.release version="0.6.1.28" date="2007/02/15" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2007-07-19 13:05:44 $">
|
||||
<i2p.release version="0.6.1.29" 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,16 +10,26 @@
|
||||
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" />
|
||||
•
|
||||
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.
|
||||
2007-07-19:
|
||||
We need bandwidth!
|
||||
Please help the network by
|
||||
<a href="/config.jsp">increasing your bandwidth limits and share percentage</a>.
|
||||
Unless the share percentage times the minimum rate is more than 16KBps,
|
||||
you are not sharing at all!
|
||||
Increasing your rate limits will also help your own transfer rates.
|
||||
Thanks!
|
||||
<br />
|
||||
•
|
||||
2007-03-13:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-March/001338.html">status notes</a>
|
||||
2007-03-17: 0.6.1.28
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-March/001340.html">released</a>
|
||||
with
|
||||
streaming lib optimizations, i2psnark
|
||||
improvements, and priority operation within the router.
|
||||
<br />
|
||||
•
|
||||
2007-04-10:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-April/001343.html">status notes</a>
|
||||
and
|
||||
<a href="http://www.i2p/meeting202">meeting log</a>
|
||||
<a href="http://www.i2p/meeting206">meeting log</a>
|
||||
<br />
|
||||
</i2p.news>
|
||||
|
30
readme.html
30
readme.html
@@ -1,5 +1,5 @@
|
||||
<p>If you've just started I2P, the Active: number on the left should start to
|
||||
grow over the next few minutes and you'll see some local "destinations" listed
|
||||
<p>If you've just started I2P, the Active: numbers on the left should start to
|
||||
grow over the next few minutes and you'll see a "shared clients" local destination listed
|
||||
on the left (if not, <a href="#trouble">see below</a>). Once those show up,
|
||||
you can:</p>
|
||||
<ul>
|
||||
@@ -12,9 +12,10 @@ you can:</p>
|
||||
browse to an eepsite -
|
||||
<ul>
|
||||
<li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li>
|
||||
<li><a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p</a>: a site which tracks active eepsites</li>
|
||||
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
|
||||
<li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li>
|
||||
<li><a href="http://search.i2p/">search.i2p</a>: an anonymously hosted search engine of eepsites</li>
|
||||
<li><a href="http://eepsites.i2p/">eepsites.i2p</a>: an anonymously hosted search engine of eepsites</li>
|
||||
<li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
|
||||
<li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li>
|
||||
<li>Freenet proxy: <a href="http://fproxy.tino.i2p">fproxy.tino.i2p</a></li>
|
||||
@@ -27,8 +28,7 @@ you can:</p>
|
||||
through the I2P network.</li>
|
||||
<li><b>transfer files</b> - there is an integrated <a href="i2psnark/">port</a> of the
|
||||
<a href="http://www.klomp.org/snark/">Snark</a> <a href="http://www.bittorrent.com/">BitTorrent</a>
|
||||
client, which is compatible with the Python
|
||||
<a href="http://i2p-bt.postman.i2p/">mainline I2P-BT</a>.</li>
|
||||
client.</li>
|
||||
<li><b>use anonymous email</b> - postman has created a mail system compatible with normal mail
|
||||
clients (POP3 / SMTP) that allows email within I2P as well as mail from and to the normal
|
||||
internet! get your account at <a href="http://hq.postman.i2p/">hq.postman.i2p</a>.
|
||||
@@ -44,18 +44,20 @@ 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. 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
|
||||
ugha's <a href="http://ugha.i2p/I2pLinks">wiki</a>, <a href="http://orion.i2p/">orion's list</a>, or paste it in the #i2p or #i2p-chat channels on
|
||||
IRC (be sure to split it into two lines, as its too long for one).</p>
|
||||
and they'll show up. After starting up an <a href="/i2ptunnel/">eepsite tunnel</a> pointing at it, your eepsite
|
||||
will be visible to others.
|
||||
Detailed instructions for starting your eepsite are on
|
||||
<a href="http://localhost:7658/">your temporary eepsite page</a>.
|
||||
</p>
|
||||
|
||||
<h2><a name="trouble">Troubleshooting</a></h2>
|
||||
|
||||
<p>If, after 5 or 10 minutes, your Active: x/y count has less than 20 active
|
||||
peers, you may want to review the information on the
|
||||
<p>Be patient - I2P may be slow to start the first time as it searches for peers.
|
||||
If, after 30 minutes, your Active: connected/recent count has less than 10 connected
|
||||
peers, you should open port 8887 on your firewall for better connectivity.
|
||||
If you cannot see any eepsites at all (even <a href="http://www.i2p">www.i2p</a>),
|
||||
be sure your browser proxy is set to localhost port 4444.
|
||||
You may also want to review the information on the
|
||||
<a href="http://www.i2p.net/">I2P website</a>, post up messages to the
|
||||
<a href="http://forum.i2p.net/">I2P discussion forum</a>, or swing by #i2p or
|
||||
#i2p-chat on IRC at <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p or irc.freshcoffee.i2p (they're linked together).</p>
|
||||
|
@@ -14,6 +14,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.i2p.data.RouterAddress;
|
||||
|
||||
/**
|
||||
* Manages the communication subsystem between peers, including connections,
|
||||
@@ -52,6 +53,10 @@ public abstract class CommSystemFacade implements Service {
|
||||
public short getReachabilityStatus() { return STATUS_OK; }
|
||||
public void recheckReachability() {}
|
||||
|
||||
/**
|
||||
* Tell other transports our address changed
|
||||
*/
|
||||
public void notifyReplaceAddress(RouterAddress UDPAddr) {}
|
||||
/**
|
||||
* We are able to receive unsolicited connections
|
||||
*/
|
||||
|
@@ -363,7 +363,7 @@ public class Router {
|
||||
|
||||
// publicize our ballpark capacity - this does not affect anything at
|
||||
// the moment
|
||||
public static final char CAPABILITY_BW16 = 'K';
|
||||
public static final char CAPABILITY_BW12 = 'K';
|
||||
public static final char CAPABILITY_BW32 = 'L';
|
||||
public static final char CAPABILITY_BW64 = 'M';
|
||||
public static final char CAPABILITY_BW128 = 'N';
|
||||
@@ -382,8 +382,8 @@ public class Router {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Adding capabilities w/ bw limit @ " + bwLim, new Exception("caps"));
|
||||
|
||||
if (bwLim <= 16) {
|
||||
ri.addCapability(CAPABILITY_BW16);
|
||||
if (bwLim < 12) {
|
||||
ri.addCapability(CAPABILITY_BW12);
|
||||
} else if (bwLim <= 32) {
|
||||
ri.addCapability(CAPABILITY_BW32);
|
||||
} else if (bwLim <= 64) {
|
||||
|
@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
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 String ID = "$Revision: 1.518 $ $Date: 2007-08-13 14:43:01 $";
|
||||
public final static String VERSION = "0.6.1.29";
|
||||
public final static long BUILD = 0;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
|
@@ -26,6 +26,7 @@ import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.ntcp.NTCPAddress;
|
||||
import net.i2p.router.transport.ntcp.NTCPTransport;
|
||||
import net.i2p.router.transport.tcp.TCPTransport;
|
||||
import net.i2p.router.transport.udp.UDPAddress;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
@@ -194,6 +195,8 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
|
||||
public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
|
||||
public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
|
||||
public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoip";
|
||||
public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoport";
|
||||
|
||||
public static RouterAddress createNTCPAddress(RouterContext ctx) {
|
||||
if (!TransportManager.enableNTCP(ctx)) return null;
|
||||
@@ -235,4 +238,80 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
//}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* UDP changed addresses, tell NTCP and restart
|
||||
*/
|
||||
public void notifyReplaceAddress(RouterAddress UDPAddr) {
|
||||
if (UDPAddr == null)
|
||||
return;
|
||||
NTCPTransport t = (NTCPTransport) _manager.getNTCPTransport();
|
||||
if (t == null)
|
||||
return;
|
||||
Properties UDPProps = UDPAddr.getOptions();
|
||||
if (UDPProps == null)
|
||||
return;
|
||||
Properties newProps;
|
||||
RouterAddress oldAddr = t.getCurrentAddress();
|
||||
//_log.warn("Changing NTCP Address? was " + oldAddr);
|
||||
RouterAddress newAddr = oldAddr;
|
||||
if (newAddr == null) {
|
||||
newAddr = new RouterAddress();
|
||||
newAddr.setCost(10);
|
||||
newAddr.setExpiration(null);
|
||||
newAddr.setTransportStyle(NTCPTransport.STYLE);
|
||||
newProps = new Properties();
|
||||
} else {
|
||||
newProps = newAddr.getOptions();
|
||||
if (newProps == null)
|
||||
newProps = new Properties();
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
String oport = newProps.getProperty(NTCPAddress.PROP_PORT);
|
||||
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_PORT, "false");
|
||||
if ( (enabled != null) && ("true".equalsIgnoreCase(enabled)) ) {
|
||||
String nport = UDPProps.getProperty(UDPAddress.PROP_PORT);
|
||||
if (nport == null || nport.length() <= 0)
|
||||
return;
|
||||
if (oport == null || ! oport.equals(nport)) {
|
||||
newProps.setProperty(NTCPAddress.PROP_PORT, nport);
|
||||
changed = true;
|
||||
}
|
||||
} else if (oport == null || oport.length() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String ohost = newProps.getProperty(NTCPAddress.PROP_HOST);
|
||||
enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "false");
|
||||
if ( (enabled != null) && ("true".equalsIgnoreCase(enabled)) ) {
|
||||
String nhost = UDPProps.getProperty(UDPAddress.PROP_HOST);
|
||||
if (nhost == null || nhost.length() <= 0)
|
||||
return;
|
||||
if (ohost == null || ! ohost.equalsIgnoreCase(nhost)) {
|
||||
newProps.setProperty(NTCPAddress.PROP_HOST, nhost);
|
||||
changed = true;
|
||||
}
|
||||
} else if (ohost == null || ohost.length() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
//_log.warn("No change to NTCP Address");
|
||||
return;
|
||||
}
|
||||
|
||||
// stopListening stops the pumper, readers, and writers, so required even if
|
||||
// oldAddr == null since startListening starts them all again
|
||||
_log.warn("Halting NTCP to change address");
|
||||
t.stopListening();
|
||||
newAddr.setOptions(newProps);
|
||||
// Give NTCP Pumper time to stop so we don't end up with two...
|
||||
// Need better way
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
t.restartListening(newAddr);
|
||||
_log.warn("Changed NTCP Address and started up, address is now " + newAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -367,7 +367,10 @@ public abstract class TransportImpl implements Transport {
|
||||
* one.
|
||||
*/
|
||||
protected void replaceAddress(RouterAddress address) {
|
||||
// _log.error("Replacing address for " + getStyle() + " was " + _currentAddress + " now " + address);
|
||||
_currentAddress = address;
|
||||
if ("SSU".equals(getStyle()))
|
||||
_context.commSystem().notifyReplaceAddress(address);
|
||||
}
|
||||
|
||||
/** Who to notify on message availability */
|
||||
|
@@ -124,6 +124,15 @@ public class TransportManager implements TransportEventListener {
|
||||
_transports.clear();
|
||||
}
|
||||
|
||||
public Transport getNTCPTransport() {
|
||||
for (int i = 0; i < _transports.size(); i++) {
|
||||
Transport t = (Transport)_transports.get(i);
|
||||
if("NTCP".equals(t.getStyle()))
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int getTransportCount() { return _transports.size(); }
|
||||
|
||||
private boolean isSupported(Set addresses, Transport t) {
|
||||
|
@@ -379,7 +379,21 @@ public class NTCPTransport extends TransportImpl {
|
||||
_writer.startWriting(NUM_CONCURRENT_WRITERS);
|
||||
|
||||
configureLocalAddress();
|
||||
return bindAddress();
|
||||
}
|
||||
|
||||
public RouterAddress restartListening(RouterAddress addr) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Restarting ntcp transport listening");
|
||||
_pumper.startPumping();
|
||||
|
||||
_reader.startReading(NUM_CONCURRENT_READERS);
|
||||
_writer.startWriting(NUM_CONCURRENT_WRITERS);
|
||||
|
||||
_myAddress = new NTCPAddress(addr);
|
||||
return bindAddress();
|
||||
}
|
||||
|
||||
private RouterAddress bindAddress() {
|
||||
if (_myAddress != null) {
|
||||
try {
|
||||
ServerSocketChannel chan = ServerSocketChannel.open();
|
||||
|
@@ -73,9 +73,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
|
||||
/** shared fast bid for connected peers */
|
||||
private TransportBid _fastBid;
|
||||
/** shared slow bid for unconnected peers */
|
||||
private TransportBid _slowBid;
|
||||
/** shared slow bid for unconnected peers when we want to prefer UDP */
|
||||
private TransportBid _slowBid;
|
||||
/** shared slow bid for unconnected peers */
|
||||
private TransportBid _slowestBid;
|
||||
/** shared fast bid for unconnected peers when we want to prefer UDP */
|
||||
private TransportBid _fastPreferredBid;
|
||||
/** shared slow bid for unconnected peers when we want to always prefer UDP */
|
||||
private TransportBid _slowPreferredBid;
|
||||
|
||||
/** list of RemoteHostId for peers whose packets we want to drop outright */
|
||||
@@ -92,14 +96,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
/** define this to explicitly set an external port */
|
||||
public static final String PROP_EXTERNAL_PORT = "i2np.udp.port";
|
||||
/**
|
||||
* If i2np.udp.alwaysPreferred is set, the UDP bids will always be under
|
||||
* If i2np.udp.preferred is set to "always", the UDP bids will always be under
|
||||
* the bid from the TCP transport - even if a TCP connection already
|
||||
* exists. If this is true (the default), it will always prefer UDP, otherwise
|
||||
* exists. If it is set to "true",
|
||||
* it will prefer UDP unless no UDP session exists and a TCP connection
|
||||
* already exists.
|
||||
* If it is set to "false" (the default),
|
||||
* it will prefer TCP unless no TCP session exists and a UDP connection
|
||||
* already exists.
|
||||
*/
|
||||
public static final String PROP_ALWAYS_PREFER_UDP = "i2np.udp.alwaysPreferred";
|
||||
private static final String DEFAULT_ALWAYS_PREFER_UDP = "true";
|
||||
public static final String PROP_PREFER_UDP = "i2np.udp.preferred";
|
||||
private static final String DEFAULT_PREFER_UDP = "false";
|
||||
|
||||
public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort";
|
||||
private static final String DEFAULT_FIXED_PORT = "true";
|
||||
@@ -139,8 +146,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_activeThrottle = mq;
|
||||
|
||||
_fastBid = new SharedBid(50);
|
||||
_slowBid = new SharedBid(1000);
|
||||
_slowPreferredBid = new SharedBid(75);
|
||||
_slowBid = new SharedBid(65);
|
||||
_fastPreferredBid = new SharedBid(15);
|
||||
_slowPreferredBid = new SharedBid(20);
|
||||
_slowestBid = new SharedBid(1000);
|
||||
|
||||
_fragments = new OutboundMessageFragments(_context, this, _activeThrottle);
|
||||
_inboundFragments = new InboundMessageFragments(_context, _fragments, this);
|
||||
@@ -843,7 +852,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (peer != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("bidding on a message to an established peer: " + peer);
|
||||
return _fastBid;
|
||||
if (preferUDP())
|
||||
return _fastPreferredBid;
|
||||
else
|
||||
return _fastBid;
|
||||
} else {
|
||||
if (null == toAddress.getTargetAddress(STYLE))
|
||||
return null;
|
||||
@@ -852,14 +864,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_log.debug("bidding on a message to an unestablished peer: " + to.toBase64());
|
||||
if (alwaysPreferUDP())
|
||||
return _slowPreferredBid;
|
||||
else
|
||||
else if (preferUDP())
|
||||
return _slowBid;
|
||||
else
|
||||
return _slowestBid;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean preferUDP() {
|
||||
String pref = _context.getProperty(PROP_PREFER_UDP, DEFAULT_PREFER_UDP);
|
||||
return (pref != null) && ! "false".equals(pref);
|
||||
}
|
||||
|
||||
private boolean alwaysPreferUDP() {
|
||||
String pref = _context.getProperty(PROP_ALWAYS_PREFER_UDP, DEFAULT_ALWAYS_PREFER_UDP);
|
||||
return (pref != null) && "true".equals(pref);
|
||||
String pref = _context.getProperty(PROP_PREFER_UDP, DEFAULT_PREFER_UDP);
|
||||
return (pref != null) && "always".equals(pref);
|
||||
}
|
||||
|
||||
private static final int MAX_IDLE_TIME = 5*60*1000;
|
||||
|
@@ -277,7 +277,7 @@ public abstract class TunnelPeerSelector {
|
||||
|
||||
private static char[] getExcludeCaps(RouterContext ctx) {
|
||||
String excludeCaps = ctx.getProperty("router.excludePeerCaps",
|
||||
String.valueOf(Router.CAPABILITY_BW16));
|
||||
String.valueOf(Router.CAPABILITY_BW12));
|
||||
Set peers = new HashSet();
|
||||
if (excludeCaps != null) {
|
||||
char excl[] = excludeCaps.toCharArray();
|
||||
|
@@ -34,6 +34,9 @@ public class TunnelPool {
|
||||
private long _lastSelectionPeriod;
|
||||
private int _expireSkew;
|
||||
private long _started;
|
||||
private long _lastRateUpdate;
|
||||
private long _lastLifetimeProcessed;
|
||||
private String _rateName;
|
||||
|
||||
public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) {
|
||||
_context = ctx;
|
||||
@@ -48,12 +51,19 @@ public class TunnelPool {
|
||||
_lifetimeProcessed = 0;
|
||||
_expireSkew = _context.random().nextInt(90*1000);
|
||||
_started = System.currentTimeMillis();
|
||||
_lastRateUpdate = _started;
|
||||
_lastLifetimeProcessed = 0;
|
||||
_rateName = "tunnel.Bps." +
|
||||
(_settings.isExploratory() ? "exploratory" : _settings.getDestinationNickname()) +
|
||||
(_settings.isInbound() ? ".in" : ".out");
|
||||
refreshSettings();
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
_alive = true;
|
||||
_started = System.currentTimeMillis();
|
||||
_lastRateUpdate = _started;
|
||||
_lastLifetimeProcessed = 0;
|
||||
_manager.getExecutor().repoll();
|
||||
if (_settings.isInbound() && (_settings.getDestination() != null) ) {
|
||||
// we just reconnected and didn't require any new tunnel builders.
|
||||
@@ -66,6 +76,9 @@ public class TunnelPool {
|
||||
if (ls != null)
|
||||
_context.clientManager().requestLeaseSet(_settings.getDestination(), ls);
|
||||
}
|
||||
_context.statManager().createRateStat(_rateName,
|
||||
"Tunnel Bandwidth", "Tunnels",
|
||||
new long[] { 5*60*1000l });
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@@ -249,6 +262,7 @@ public class TunnelPool {
|
||||
_manager.getExecutor().repoll();
|
||||
|
||||
_lifetimeProcessed += info.getProcessedMessagesCount();
|
||||
updateRate();
|
||||
|
||||
long lifetimeConfirmed = info.getVerifiedBytesTransferred();
|
||||
long lifetime = 10*60*1000;
|
||||
@@ -295,6 +309,7 @@ public class TunnelPool {
|
||||
_manager.tunnelFailed();
|
||||
|
||||
_lifetimeProcessed += cfg.getProcessedMessagesCount();
|
||||
updateRate();
|
||||
|
||||
if (_settings.isInbound() && (_settings.getDestination() != null) ) {
|
||||
if (ls != null) {
|
||||
@@ -303,6 +318,17 @@ public class TunnelPool {
|
||||
}
|
||||
}
|
||||
|
||||
void updateRate() {
|
||||
long now = _context.clock().now();
|
||||
long et = now - _lastRateUpdate;
|
||||
if (et > 2*60*1000) {
|
||||
long bw = 1024 * (_lifetimeProcessed - _lastLifetimeProcessed) * 1000 / et; // Bps
|
||||
_context.statManager().addRateData(_rateName, bw, 0);
|
||||
_lastRateUpdate = now;
|
||||
_lastLifetimeProcessed = _lifetimeProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
void refreshLeaseSet() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(toString() + ": refreshing leaseSet on tunnel expiration (but prior to grace timeout)");
|
||||
|
@@ -535,14 +535,14 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
||||
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
|
||||
if (info != null) {
|
||||
String caps = info.getCapabilities();
|
||||
if (caps.indexOf(Router.CAPABILITY_BW16) >= 0) {
|
||||
return "[<16 ]";
|
||||
if (caps.indexOf(Router.CAPABILITY_BW12) >= 0) {
|
||||
return "[<12 ]";
|
||||
} else if (caps.indexOf(Router.CAPABILITY_BW32) >= 0) {
|
||||
return "[<32 ]";
|
||||
return "[<=32 ]";
|
||||
} else if (caps.indexOf(Router.CAPABILITY_BW64) >= 0) {
|
||||
return "[<64 ]";
|
||||
return "[<=64 ]";
|
||||
} else if (caps.indexOf(Router.CAPABILITY_BW128) >= 0) {
|
||||
return "<b>[<128]</b>";
|
||||
return "<b>[<=128]</b>";
|
||||
} else if (caps.indexOf(Router.CAPABILITY_BW256) >= 0) {
|
||||
return "<b>[>128]</b>";
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user