forked from I2P_Developers/i2p.i2p
Compare commits
118 Commits
i2p_0_6_1_
...
i2p-0.6.1.
Author | SHA1 | Date | |
---|---|---|---|
aebf16add7 | |||
1de0563c94 | |||
![]() |
c6059b9d85 | ||
![]() |
f68c9242a9 | ||
51838ba051 | |||
cf50b7eac1 | |||
2edd84e088 | |||
5ba1e458c6 | |||
0b600669c7 | |||
![]() |
215eb14d38 | ||
20ff2f5bdc | |||
edc02e5efa | |||
d57356f807 | |||
a7a6c75ac5 | |||
b9e2def552 | |||
4d7417401c | |||
40a9e959e8 | |||
42bbb4a9ff | |||
9500a55532 | |||
0556f15068 | |||
6e981874a5 | |||
8886d61caa | |||
b6fe81a982 | |||
e7cdb965ba | |||
4fa4357bf1 | |||
46307c60d4 | |||
e6a0c2f4f0 | |||
cb41bf6023 | |||
d23c8a8331 | |||
b1beb46ca2 | |||
![]() |
6606c83cb2 | ||
5998f5c9bd | |||
cffcbe5f94 | |||
0c75725f5e | |||
5ef325408c | |||
d957712e88 | |||
9233c2ed4c | |||
7ad54eb749 | |||
5740e20c62 | |||
0a9114fc2f | |||
71ddfa42e1 | |||
1ecb84f3fb | |||
c46b06fb81 | |||
a7397879aa | |||
9b86da7ce5 | |||
c68977ca8c | |||
bc7bd628db | |||
bc7ab39131 | |||
100163e03b | |||
49c02f13b2 | |||
40f072e25e | |||
918b1acb8f | |||
bc16078e3f | |||
4a8dbd0634 | |||
38c0184f95 | |||
68829ddb99 | |||
19089bd6a7 | |||
69cc0afd1b | |||
d2f3a262db | |||
![]() |
c1703b872d | ||
![]() |
f7b0e8181b | ||
43f2695901 | |||
![]() |
ea0d4ffd7f | ||
![]() |
0ed29573a7 | ||
1365d3e3b9 | |||
40befb5a92 | |||
9c16eec361 | |||
093c69637d | |||
134ec7acea | |||
![]() |
0802a5ae40 | ||
![]() |
14ddfb360f | ||
![]() |
78ad831028 | ||
22f1684262 | |||
83f51b4a66 | |||
9c28de0704 | |||
c69fda2298 | |||
cabb22331b | |||
![]() |
5b3aca29a8 | ||
![]() |
f35cbf59d8 | ||
![]() |
a96119d09b | ||
![]() |
2711294aee | ||
![]() |
f838b1828b | ||
![]() |
fbf6282c1a | ||
![]() |
5195a5c1fc | ||
![]() |
62b18b18b5 | ||
![]() |
7c8f519b35 | ||
![]() |
d6fb979616 | ||
![]() |
f568d21969 | ||
![]() |
7fe9d590f5 | ||
![]() |
0a1240ebfd | ||
![]() |
4e68f2a157 | ||
![]() |
e9bd6907d1 | ||
![]() |
b20495c39f | ||
![]() |
0ecbc4c27b | ||
![]() |
4d5b1d4c3f | ||
![]() |
17b719f3f7 | ||
![]() |
979a3e98d8 | ||
![]() |
c6a1112f0a | ||
![]() |
4ebcc95d9f | ||
![]() |
7e59ce27fa | ||
![]() |
22345a264e | ||
![]() |
03739996da | ||
![]() |
819a72d4f6 | ||
![]() |
e480931e20 | ||
![]() |
3f01d0a69e | ||
![]() |
f67f47f0cd | ||
![]() |
5ad6ee60eb | ||
![]() |
5accba6cdc | ||
![]() |
313e1704df | ||
![]() |
cf4d2b17c9 | ||
![]() |
9145eedc35 | ||
![]() |
b772179077 | ||
![]() |
9054a196ce | ||
![]() |
d28a96ac7d | ||
![]() |
9c73f80ac3 | ||
![]() |
20c46cff04 | ||
![]() |
f332513755 | ||
![]() |
cb69a66498 |
@@ -17,6 +17,10 @@
|
||||
# Contains the addresses from your master address book
|
||||
# and your subscribed address books. (../userhosts.txt)
|
||||
#
|
||||
# private_addressbook The path to the private address book used by the router.
|
||||
# This is used only by the router and SusiDNS.
|
||||
# It is not published by addressbook. (../privatehosts.txt)
|
||||
#
|
||||
# published_addressbook The path to the copy of your address book made
|
||||
# available on i2p. (../eepsite/docroot/hosts.txt)
|
||||
#
|
||||
@@ -35,6 +39,7 @@ proxy_host=localhost
|
||||
proxy_port=4444
|
||||
master_addressbook=myhosts.txt
|
||||
router_addressbook=../userhosts.txt
|
||||
private_addressbook=../privatehosts.txt
|
||||
published_addressbook=../eepsite/docroot/hosts.txt
|
||||
log=log.txt
|
||||
subscriptions=subscriptions.txt
|
||||
|
@@ -66,6 +66,7 @@ public class AddressBook {
|
||||
* where key is a human readable name, and value is a base64 i2p
|
||||
* destination.
|
||||
*/
|
||||
/* unused
|
||||
public AddressBook(String url, String proxyHost, int proxyPort) {
|
||||
this.location = url;
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
@@ -79,22 +80,26 @@ public class AddressBook {
|
||||
}
|
||||
new File("addressbook.tmp").delete();
|
||||
}
|
||||
|
||||
*/
|
||||
/**
|
||||
* Construct an AddressBook from the Subscription subscription. If the
|
||||
* address book at subscription has not changed since the last time it was
|
||||
* read or cannot be read, return an empty AddressBook.
|
||||
* Set a maximum size of the remote book to make it a little harder for a malicious book-sender.
|
||||
*
|
||||
* @param subscription
|
||||
* A Subscription instance pointing at a remote address book.
|
||||
*/
|
||||
static final long MAX_SUB_SIZE = 3 * 1024 * 1024l; //about 5,000 hosts
|
||||
public AddressBook(Subscription subscription, String proxyHost, int proxyPort) {
|
||||
this.location = subscription.getLocation();
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, "addressbook.tmp",
|
||||
subscription.getLocation(), true, subscription.getEtag());
|
||||
get.fetch();
|
||||
subscription.setEtag(get.getETag());
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, "addressbook.tmp", null,
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
}
|
||||
try {
|
||||
this.addresses = ConfigParser.parse(new File("addressbook.tmp"));
|
||||
} catch (IOException exp) {
|
||||
@@ -151,6 +156,37 @@ public class AddressBook {
|
||||
return this.addresses.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do basic validation of the hostname and dest
|
||||
* hostname was already converted to lower case by ConfigParser.parse()
|
||||
*/
|
||||
private static boolean valid(String host, String dest) {
|
||||
return
|
||||
host.endsWith(".i2p") &&
|
||||
host.length() > 4 &&
|
||||
host.length() <= 67 && // 63 + ".i2p"
|
||||
(! host.startsWith(".")) &&
|
||||
(! host.startsWith("-")) &&
|
||||
host.indexOf(".-") < 0 &&
|
||||
host.indexOf("-.") < 0 &&
|
||||
host.indexOf("..") < 0 &&
|
||||
// IDN - basic check, not complete validation
|
||||
(host.indexOf("--") < 0 || host.startsWith("xn--") || host.indexOf(".xn--") > 0) &&
|
||||
host.replaceAll("[a-z0-9.-]", "").length() == 0 &&
|
||||
// some reserved names that may be used for local configuration someday
|
||||
(! host.equals("proxy.i2p")) &&
|
||||
(! host.equals("router.i2p")) &&
|
||||
(! host.equals("console.i2p")) &&
|
||||
(! host.endsWith(".proxy.i2p")) &&
|
||||
(! host.endsWith(".router.i2p")) &&
|
||||
(! host.endsWith(".console.i2p")) &&
|
||||
|
||||
dest.length() == 516 &&
|
||||
dest.endsWith("AAAA") &&
|
||||
dest.replaceAll("[a-zA-Z0-9~-]", "").length() == 0
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this AddressBook with AddressBook other, writing messages about new
|
||||
* addresses or conflicts to log. Addresses in AddressBook other that are
|
||||
@@ -169,7 +205,7 @@ public class AddressBook {
|
||||
String otherKey = (String) otherIter.next();
|
||||
String otherValue = (String) other.addresses.get(otherKey);
|
||||
|
||||
if (otherKey.endsWith(".i2p") && otherValue.length() >= 516) {
|
||||
if (valid(otherKey, otherValue)) {
|
||||
if (this.addresses.containsKey(otherKey) && !overwrite) {
|
||||
if (!this.addresses.get(otherKey).equals(otherValue)
|
||||
&& log != null) {
|
||||
@@ -184,7 +220,7 @@ public class AddressBook {
|
||||
this.modified = true;
|
||||
if (log != null) {
|
||||
log.append("New address " + otherKey
|
||||
+ " added to address book.");
|
||||
+ " added to address book. From: " + other.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -60,6 +60,7 @@ public class ConfigParser {
|
||||
* a single key, value pair on each line, in the format: key=value. Lines
|
||||
* starting with '#' or ';' are considered comments, and ignored. Lines that
|
||||
* are obviously not in the format key=value are also ignored.
|
||||
* The key is converted to lower case.
|
||||
*
|
||||
* @param input
|
||||
* A BufferedReader with lines in key=value format to parse into
|
||||
@@ -77,7 +78,7 @@ public class ConfigParser {
|
||||
inputLine = ConfigParser.stripComments(inputLine);
|
||||
String[] splitLine = inputLine.split("=");
|
||||
if (splitLine.length == 2) {
|
||||
result.put(splitLine[0].trim(), splitLine[1].trim());
|
||||
result.put(splitLine[0].trim().toLowerCase(), splitLine[1].trim());
|
||||
}
|
||||
inputLine = input.readLine();
|
||||
}
|
||||
@@ -301,4 +302,4 @@ public class ConfigParser {
|
||||
new FileWriter(file, false)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -98,7 +98,8 @@ public class Daemon {
|
||||
AddressBook router = new AddressBook(routerFile);
|
||||
|
||||
List defaultSubs = new LinkedList();
|
||||
defaultSubs.add("http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/hosts.txt");
|
||||
// defaultSubs.add("http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/hosts.txt");
|
||||
defaultSubs.add("http://www.i2p2.i2p/hosts.txt");
|
||||
|
||||
SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
|
||||
etagsFile, lastModifiedFile, defaultSubs, (String) settings
|
||||
|
@@ -14,7 +14,7 @@
|
||||
srcdir="./src"
|
||||
debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="./build/obj"
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
|
||||
classpath="../../../core/java/build/i2p.jar:../../../router/java/build/router.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
|
||||
</target>
|
||||
<target name="jar" depends="builddep, compile">
|
||||
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/*Servlet.class">
|
||||
|
@@ -34,6 +34,7 @@ public class I2PSnarkUtil {
|
||||
private boolean _configured;
|
||||
private Set _shitlist;
|
||||
private int _maxUploaders;
|
||||
private int _maxUpBW;
|
||||
|
||||
private I2PSnarkUtil() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
@@ -79,6 +80,11 @@ public class I2PSnarkUtil {
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setMaxUpBW(int limit) {
|
||||
_maxUpBW = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public String getI2CPHost() { return _i2cpHost; }
|
||||
public int getI2CPPort() { return _i2cpPort; }
|
||||
public Map getI2CPOptions() { return _opts; }
|
||||
@@ -86,11 +92,12 @@ public class I2PSnarkUtil {
|
||||
public int getEepProxyPort() { return _proxyPort; }
|
||||
public boolean getEepProxySet() { return _shouldProxy; }
|
||||
public int getMaxUploaders() { return _maxUploaders; }
|
||||
public int getMaxUpBW() { return _maxUpBW; }
|
||||
|
||||
/**
|
||||
* Connect to the router, if we aren't already
|
||||
*/
|
||||
public boolean connect() {
|
||||
synchronized public boolean connect() {
|
||||
if (_manager == null) {
|
||||
Properties opts = new Properties();
|
||||
if (_opts != null) {
|
||||
@@ -104,9 +111,9 @@ public class I2PSnarkUtil {
|
||||
if (opts.getProperty("outbound.nickname") == null)
|
||||
opts.setProperty("outbound.nickname", "I2PSnark");
|
||||
if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
|
||||
opts.setProperty("i2p.streaming.inactivityTimeout", "90000");
|
||||
opts.setProperty("i2p.streaming.inactivityTimeout", "240000");
|
||||
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
|
||||
opts.setProperty("i2p.streaming.inactivityAction", "2"); // 1 == disconnect, 2 == ping
|
||||
opts.setProperty("i2p.streaming.inactivityAction", "1"); // 1 == disconnect, 2 == ping
|
||||
if (opts.getProperty("i2p.streaming.initialWindowSize") == null)
|
||||
opts.setProperty("i2p.streaming.initialWindowSize", "1");
|
||||
if (opts.getProperty("i2p.streaming.slowStartGrowthRateFactor") == null)
|
||||
@@ -160,8 +167,10 @@ public class I2PSnarkUtil {
|
||||
/**
|
||||
* fetch the given URL, returning the file it is stored in, or null on error
|
||||
*/
|
||||
public File get(String url) { return get(url, true); }
|
||||
public File get(String url, boolean rewrite) {
|
||||
public File get(String url) { return get(url, true, 0); }
|
||||
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
|
||||
public File get(String url, int retries) { return get(url, true, retries); }
|
||||
public File get(String url, boolean rewrite, int retries) {
|
||||
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
||||
File out = null;
|
||||
try {
|
||||
@@ -175,7 +184,7 @@ public class I2PSnarkUtil {
|
||||
if (rewrite)
|
||||
fetchURL = rewriteAnnounce(url);
|
||||
//_log.debug("Rewritten url [" + fetchURL + "]");
|
||||
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, 1, out.getAbsolutePath(), fetchURL);
|
||||
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
||||
if (get.fetch()) {
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||
return out;
|
||||
@@ -195,6 +204,8 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
|
||||
String getOurIPString() {
|
||||
if (_manager == null)
|
||||
return "unknown";
|
||||
I2PSession sess = _manager.getSession();
|
||||
if (sess != null) {
|
||||
Destination dest = sess.getMyDestination();
|
||||
@@ -206,15 +217,15 @@ public class I2PSnarkUtil {
|
||||
Destination getDestination(String ip) {
|
||||
if (ip == null) return null;
|
||||
if (ip.endsWith(".i2p")) {
|
||||
Destination dest = _context.namingService().lookup(ip);
|
||||
if (dest != null) {
|
||||
return dest;
|
||||
} else {
|
||||
try {
|
||||
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
|
||||
} catch (DataFormatException dfe) {
|
||||
return null;
|
||||
}
|
||||
if (ip.length() < 520) { // key + ".i2p"
|
||||
Destination dest = _context.namingService().lookup(ip);
|
||||
if (dest != null)
|
||||
return dest;
|
||||
}
|
||||
try {
|
||||
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
|
||||
} catch (DataFormatException dfe) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@@ -225,12 +236,22 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public String lookup(String name) {
|
||||
Destination dest = getDestination(name);
|
||||
if (dest == null)
|
||||
return null;
|
||||
return dest.toBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given http://blah.i2p/foo/announce turn it into http://i2p/blah/foo/announce
|
||||
* Given http://KEY.i2p/foo/announce turn it into http://i2p/KEY/foo/announce
|
||||
* Given http://tracker.blah.i2p/foo/announce leave it alone
|
||||
*/
|
||||
String rewriteAnnounce(String origAnnounce) {
|
||||
int destStart = "http://".length();
|
||||
int destEnd = origAnnounce.indexOf(".i2p");
|
||||
if (destEnd < destStart + 516)
|
||||
return origAnnounce;
|
||||
int pathStart = origAnnounce.indexOf('/', destEnd);
|
||||
String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
|
||||
//_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");
|
||||
|
@@ -114,6 +114,14 @@ public class Peer implements Comparable
|
||||
return "[unknown id] " + _id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socket (for debug printing)
|
||||
*/
|
||||
public String getSocket()
|
||||
{
|
||||
return sock.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code of a Peer is the hash code of the peerID.
|
||||
*/
|
||||
@@ -461,10 +469,12 @@ public class Peer implements Comparable
|
||||
public long getInactiveTime() {
|
||||
PeerState s = state;
|
||||
if (s != null) {
|
||||
PeerConnectionIn in = s.in;
|
||||
PeerConnectionOut out = s.out;
|
||||
if (out != null)
|
||||
return System.currentTimeMillis() - out.lastSent;
|
||||
else
|
||||
if (in != null && out != null) {
|
||||
long now = System.currentTimeMillis();
|
||||
return Math.max(now - out.lastSent, now - in.lastRcvd);
|
||||
} else
|
||||
return -1; //"state, no out";
|
||||
} else {
|
||||
return -1; //"no state";
|
||||
|
@@ -68,6 +68,7 @@ class PeerCheckerTask extends TimerTask
|
||||
// we will add them back to the end of the list.
|
||||
List removed = new ArrayList();
|
||||
int uploadLimit = coordinator.allowedUploaders();
|
||||
boolean overBWLimit = coordinator.overUpBWLimit();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer peer = (Peer)it.next();
|
||||
@@ -95,32 +96,29 @@ class PeerCheckerTask extends TimerTask
|
||||
peer.setRateHistory(upload, download);
|
||||
peer.resetCounters();
|
||||
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
{
|
||||
Snark.debug(peer + ":", Snark.DEBUG);
|
||||
Snark.debug(" ul: " + upload/KILOPERSECOND
|
||||
+ " dl: " + download/KILOPERSECOND
|
||||
+ " i: " + peer.isInterested()
|
||||
+ " I: " + peer.isInteresting()
|
||||
+ " c: " + peer.isChoking()
|
||||
+ " C: " + peer.isChoked(),
|
||||
Snark.DEBUG);
|
||||
}
|
||||
Snark.debug(peer + ":", Snark.DEBUG);
|
||||
Snark.debug(" ul: " + upload/KILOPERSECOND
|
||||
+ " dl: " + download/KILOPERSECOND
|
||||
+ " i: " + peer.isInterested()
|
||||
+ " I: " + peer.isInteresting()
|
||||
+ " c: " + peer.isChoking()
|
||||
+ " C: " + peer.isChoked(),
|
||||
Snark.DEBUG);
|
||||
|
||||
// If we are at our max uploaders and we have lots of other
|
||||
// interested peers try to make some room.
|
||||
// (Note use of coordinator.uploaders)
|
||||
if (((coordinator.uploaders == uploadLimit
|
||||
&& coordinator.interestedAndChoking > 0)
|
||||
|| coordinator.uploaders > uploadLimit)
|
||||
|| coordinator.uploaders > uploadLimit
|
||||
|| overBWLimit)
|
||||
&& !peer.isChoking())
|
||||
{
|
||||
// Check if it still wants pieces from us.
|
||||
if (!peer.isInterested())
|
||||
{
|
||||
if (Snark.debug >= Snark.INFO)
|
||||
Snark.debug("Choke uninterested peer: " + peer,
|
||||
Snark.INFO);
|
||||
Snark.debug("Choke uninterested peer: " + peer,
|
||||
Snark.INFO);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@@ -129,11 +127,19 @@ class PeerCheckerTask extends TimerTask
|
||||
it.remove();
|
||||
removed.add(peer);
|
||||
}
|
||||
else if (overBWLimit)
|
||||
{
|
||||
Snark.debug("BW limit, choke peer: " + peer,
|
||||
Snark.INFO);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
removedCount++;
|
||||
}
|
||||
else if (peer.isInteresting() && peer.isChoked())
|
||||
{
|
||||
// If they are choking us make someone else a downloader
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
Snark.debug("Choke choking peer: " + peer, Snark.DEBUG);
|
||||
Snark.debug("Choke choking peer: " + peer, Snark.DEBUG);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@@ -146,8 +152,7 @@ class PeerCheckerTask extends TimerTask
|
||||
else if (!peer.isInteresting() && !coordinator.completed())
|
||||
{
|
||||
// If they aren't interesting make someone else a downloader
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
Snark.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
|
||||
Snark.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@@ -162,9 +167,8 @@ class PeerCheckerTask extends TimerTask
|
||||
&& download == 0)
|
||||
{
|
||||
// We are downloading but didn't receive anything...
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
Snark.debug("Choke downloader that doesn't deliver:"
|
||||
+ peer, Snark.DEBUG);
|
||||
Snark.debug("Choke downloader that doesn't deliver:"
|
||||
+ peer, Snark.DEBUG);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@@ -202,9 +206,8 @@ class PeerCheckerTask extends TimerTask
|
||||
|| uploaders > uploadLimit)
|
||||
&& worstDownloader != null)
|
||||
{
|
||||
if (Snark.debug >= Snark.DEBUG)
|
||||
Snark.debug("Choke worst downloader: " + worstDownloader,
|
||||
Snark.DEBUG);
|
||||
Snark.debug("Choke worst downloader: " + worstDownloader,
|
||||
Snark.DEBUG);
|
||||
|
||||
worstDownloader.setChoking(true);
|
||||
coordinator.uploaders--;
|
||||
@@ -217,7 +220,8 @@ class PeerCheckerTask extends TimerTask
|
||||
}
|
||||
|
||||
// Optimistically unchoke a peer
|
||||
coordinator.unchokePeer();
|
||||
if (!overBWLimit)
|
||||
coordinator.unchokePeer();
|
||||
|
||||
// Put peers back at the end of the list that we removed earlier.
|
||||
coordinator.peers.addAll(removed);
|
||||
|
@@ -35,10 +35,13 @@ class PeerConnectionIn implements Runnable
|
||||
private Thread thread;
|
||||
private volatile boolean quit;
|
||||
|
||||
long lastRcvd;
|
||||
|
||||
public PeerConnectionIn(Peer peer, DataInputStream din)
|
||||
{
|
||||
this.peer = peer;
|
||||
this.din = din;
|
||||
lastRcvd = System.currentTimeMillis();
|
||||
quit = false;
|
||||
}
|
||||
|
||||
@@ -76,6 +79,7 @@ class PeerConnectionIn implements Runnable
|
||||
// Wait till we hear something...
|
||||
// The length of a complete message in bytes.
|
||||
int i = din.readInt();
|
||||
lastRcvd = System.currentTimeMillis();
|
||||
if (i < 0)
|
||||
throw new IOException("Unexpected length prefix: " + i);
|
||||
|
||||
|
@@ -52,8 +52,8 @@ public class PeerCoordinator implements PeerListener
|
||||
private long uploaded;
|
||||
private long downloaded;
|
||||
final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long
|
||||
private long uploaded_old[] = {0,0,0,0,0,0};
|
||||
private long downloaded_old[] = {0,0,0,0,0,0};
|
||||
private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
|
||||
private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
|
||||
|
||||
// synchronize on this when changing peers or downloaders
|
||||
final List peers = new ArrayList();
|
||||
@@ -195,11 +195,17 @@ public class PeerCoordinator implements PeerListener
|
||||
private long getRate(long array[])
|
||||
{
|
||||
long rate = 0;
|
||||
int i = 0;
|
||||
synchronized(array) {
|
||||
for (int i = 0; i < RATE_DEPTH; i++)
|
||||
for ( ; i < RATE_DEPTH; i++) {
|
||||
if (array[i] < 0)
|
||||
break;
|
||||
rate += array[i];
|
||||
}
|
||||
}
|
||||
return rate / (RATE_DEPTH * CHECK_PERIOD / 1000);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
return rate / (i * CHECK_PERIOD / 1000);
|
||||
}
|
||||
|
||||
public MetaInfo getMetaInfo()
|
||||
@@ -253,8 +259,8 @@ public class PeerCoordinator implements PeerListener
|
||||
synchronized(peers)
|
||||
{
|
||||
Peer old = peerIDInList(peer.getPeerID(), peers);
|
||||
if ( (old != null) && (old.getInactiveTime() > 4*60*1000) ) {
|
||||
// idle for 4 minutes, kill the old con (64KB/4min = 273B/sec minimum for one block)
|
||||
if ( (old != null) && (old.getInactiveTime() > 8*60*1000) ) {
|
||||
// idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
|
||||
peers.remove(old);
|
||||
@@ -313,6 +319,9 @@ public class PeerCoordinator implements PeerListener
|
||||
synchronized(peers)
|
||||
{
|
||||
need_more = !peer.isConnected() && peers.size() < MAX_CONNECTIONS;
|
||||
// Check if we already have this peer before we build the connection
|
||||
Peer old = peerIDInList(peer.getPeerID(), peers);
|
||||
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
|
||||
}
|
||||
|
||||
if (need_more)
|
||||
@@ -808,13 +817,18 @@ public class PeerCoordinator implements PeerListener
|
||||
public int allowedUploaders()
|
||||
{
|
||||
if (Snark.overUploadLimit(uploaders)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Over limit, uploaders was: " + uploaders);
|
||||
// if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Over limit, uploaders was: " + uploaders);
|
||||
return uploaders - 1;
|
||||
} else if (uploaders < MAX_UPLOADERS)
|
||||
return uploaders + 1;
|
||||
else
|
||||
return MAX_UPLOADERS;
|
||||
}
|
||||
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
return Snark.overUpBWLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -63,7 +63,7 @@ public class Snark
|
||||
/**
|
||||
* What level of debug info to show.
|
||||
*/
|
||||
public static int debug = NOTICE;
|
||||
//public static int debug = NOTICE;
|
||||
|
||||
// Whether or not to ask the user for commands while sharing
|
||||
private static boolean command_interpreter = true;
|
||||
@@ -312,7 +312,7 @@ public class Snark
|
||||
else
|
||||
{
|
||||
activity = "Getting torrent";
|
||||
File torrentFile = I2PSnarkUtil.instance().get(torrent);
|
||||
File torrentFile = I2PSnarkUtil.instance().get(torrent, 3);
|
||||
if (torrentFile == null) {
|
||||
fatal("Unable to fetch " + torrent);
|
||||
if (false) return; // never reached - fatal(..) throws
|
||||
@@ -505,6 +505,7 @@ public class Snark
|
||||
int i = 0;
|
||||
while (i < args.length)
|
||||
{
|
||||
/*
|
||||
if (args[i].equals("--debug"))
|
||||
{
|
||||
debug = INFO;
|
||||
@@ -525,7 +526,7 @@ public class Snark
|
||||
catch (NumberFormatException nfe) { }
|
||||
}
|
||||
}
|
||||
else if (args[i].equals("--port"))
|
||||
else */ if (args[i].equals("--port"))
|
||||
{
|
||||
if (args.length - 1 < i + 1)
|
||||
usage("--port needs port number to listen on");
|
||||
@@ -772,7 +773,21 @@ public class Snark
|
||||
totalUploaders += c.uploaders;
|
||||
}
|
||||
int limit = I2PSnarkUtil.instance().getMaxUploaders();
|
||||
Snark.debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
|
||||
// Snark.debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
|
||||
return totalUploaders > limit;
|
||||
}
|
||||
|
||||
public static boolean overUpBWLimit() {
|
||||
PeerCoordinatorSet coordinators = PeerCoordinatorSet.instance();
|
||||
if (coordinators == null)
|
||||
return false;
|
||||
long total = 0;
|
||||
for (Iterator iter = coordinators.iterator(); iter.hasNext(); ) {
|
||||
PeerCoordinator c = (PeerCoordinator)iter.next();
|
||||
if (!c.halted())
|
||||
total += c.getUploadRate();
|
||||
}
|
||||
long limit = 1024l * I2PSnarkUtil.instance().getMaxUpBW();
|
||||
return total > limit;
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -30,13 +31,21 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
public static final String PROP_EEP_HOST = "i2psnark.eepHost";
|
||||
public static final String PROP_EEP_PORT = "i2psnark.eepPort";
|
||||
public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total";
|
||||
public static final String PROP_UPBW_MAX = "i2psnark.upbw.max";
|
||||
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 PROP_AUTO_START = "i2snark.autoStart"; // oops
|
||||
public static final String DEFAULT_AUTO_START = "false";
|
||||
public static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
|
||||
public static final String DEFAULT_USE_OPENTRACKERS = "true";
|
||||
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
|
||||
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
|
||||
|
||||
public static final int MIN_UP_BW = 2;
|
||||
public static final int DEFAULT_MAX_UP_BW = 10;
|
||||
|
||||
private SnarkManager() {
|
||||
_snarks = new HashMap();
|
||||
_addSnarkLock = new Object();
|
||||
@@ -72,6 +81,9 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
public boolean shouldAutoStart() {
|
||||
return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue();
|
||||
}
|
||||
public boolean shouldUseOpenTrackers() {
|
||||
return Boolean.valueOf(_config.getProperty(PROP_USE_OPENTRACKERS, DEFAULT_USE_OPENTRACKERS)).booleanValue();
|
||||
}
|
||||
private int getStartupDelayMinutes() { return 1; }
|
||||
public File getDataDir() {
|
||||
String dir = _config.getProperty(PROP_DIR);
|
||||
@@ -105,6 +117,12 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
_config.setProperty(PROP_EEP_PORT, "4444");
|
||||
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
|
||||
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
|
||||
if (!_config.containsKey(PROP_UPBW_MAX)) {
|
||||
if (_context instanceof RouterContext)
|
||||
_config.setProperty(PROP_UPBW_MAX, "" + (((RouterContext)_context).bandwidthLimiter().getOutboundKBytesPerSecond() / 3));
|
||||
else
|
||||
_config.setProperty(PROP_UPBW_MAX, "" + DEFAULT_MAX_UP_BW);
|
||||
}
|
||||
if (!_config.containsKey(PROP_DIR))
|
||||
_config.setProperty(PROP_DIR, "i2psnark");
|
||||
if (!_config.containsKey(PROP_AUTO_START))
|
||||
@@ -136,6 +154,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
if (eepHost != null)
|
||||
I2PSnarkUtil.instance().setProxy(eepHost, eepPort);
|
||||
I2PSnarkUtil.instance().setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
|
||||
I2PSnarkUtil.instance().setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
getDataDir().mkdirs();
|
||||
}
|
||||
|
||||
@@ -152,7 +171,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
|
||||
public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit) {
|
||||
String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) {
|
||||
boolean changed = false;
|
||||
if (eepHost != null) {
|
||||
int port = I2PSnarkUtil.instance().getEepProxyPort();
|
||||
@@ -170,7 +189,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
if (upLimit != null) {
|
||||
int limit = I2PSnarkUtil.instance().getMaxUploaders();
|
||||
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
|
||||
if ( limit != I2PSnarkUtil.instance().getEepProxyPort()) {
|
||||
if ( limit != I2PSnarkUtil.instance().getMaxUploaders()) {
|
||||
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
|
||||
I2PSnarkUtil.instance().setMaxUploaders(limit);
|
||||
changed = true;
|
||||
@@ -181,6 +200,20 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (upBW != null) {
|
||||
int limit = I2PSnarkUtil.instance().getMaxUpBW();
|
||||
try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {}
|
||||
if ( limit != I2PSnarkUtil.instance().getMaxUpBW()) {
|
||||
if ( limit >= MIN_UP_BW ) {
|
||||
I2PSnarkUtil.instance().setMaxUpBW(limit);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_UPBW_MAX, "" + limit);
|
||||
addMessage("Up BW limit changed to " + limit + "KBps");
|
||||
} else {
|
||||
addMessage("Minimum Up BW limit is " + MIN_UP_BW + "KBps");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i2cpHost != null) {
|
||||
int oldI2CPPort = I2PSnarkUtil.instance().getI2CPPort();
|
||||
String oldI2CPHost = I2PSnarkUtil.instance().getI2CPHost();
|
||||
@@ -265,6 +298,18 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
addMessage("Adjusted autostart to " + autoStart);
|
||||
changed = true;
|
||||
}
|
||||
if (shouldUseOpenTrackers() != useOpenTrackers) {
|
||||
_config.setProperty(PROP_USE_OPENTRACKERS, useOpenTrackers + "");
|
||||
addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect");
|
||||
changed = true;
|
||||
}
|
||||
if (openTrackers != null) {
|
||||
if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(getOpenTrackerString())) {
|
||||
_config.setProperty(PROP_OPENTRACKERS, openTrackers.trim());
|
||||
addMessage("Open Tracker list changed - torrent restart required to take effect");
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
saveConfig();
|
||||
} else {
|
||||
@@ -595,11 +640,12 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
private static final String DEFAULT_TRACKERS[] = {
|
||||
"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/"
|
||||
// , "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/"
|
||||
// , "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"
|
||||
, "welterde", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
|
||||
};
|
||||
|
||||
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
|
||||
@@ -634,6 +680,26 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
return trackerMap;
|
||||
}
|
||||
|
||||
public String getOpenTrackerString() {
|
||||
return _config.getProperty(PROP_OPENTRACKERS, DEFAULT_OPENTRACKERS);
|
||||
}
|
||||
|
||||
/** comma delimited list open trackers to use as backups */
|
||||
/** sorted map of name to announceURL=baseURL */
|
||||
public List getOpenTrackers() {
|
||||
if (!shouldUseOpenTrackers())
|
||||
return null;
|
||||
List rv = new ArrayList(1);
|
||||
String trackers = getOpenTrackerString();
|
||||
StringTokenizer tok = new StringTokenizer(trackers, ", ");
|
||||
while (tok.hasMoreTokens())
|
||||
rv.add(tok.nextToken());
|
||||
|
||||
if (rv.size() <= 0)
|
||||
return null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static class TorrentFilenameFilter implements FilenameFilter {
|
||||
private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter();
|
||||
public static TorrentFilenameFilter instance() { return _filter; }
|
||||
|
@@ -117,7 +117,8 @@ public class Storage
|
||||
}
|
||||
|
||||
String name = baseFile.getName();
|
||||
if (files.size() == 1)
|
||||
if (files.size() == 1) // FIXME: ...and if base file not a directory or should this be the only check?
|
||||
// this makes a bad metainfo if the directory has only one file in it
|
||||
{
|
||||
files = null;
|
||||
lengthsList = null;
|
||||
@@ -406,7 +407,7 @@ public class Storage
|
||||
/**
|
||||
* Removes 'suspicious' characters from the give file name.
|
||||
*/
|
||||
private String filterName(String name)
|
||||
private static String filterName(String name)
|
||||
{
|
||||
// XXX - Is this enough?
|
||||
return name.replace(File.separatorChar, '_');
|
||||
@@ -438,7 +439,7 @@ public class Storage
|
||||
return f;
|
||||
}
|
||||
|
||||
private File getFileFromNames(File base, List names) throws IOException
|
||||
public static File getFileFromNames(File base, List names)
|
||||
{
|
||||
Iterator it = names.iterator();
|
||||
while (it.hasNext())
|
||||
|
@@ -46,6 +46,10 @@ public class TrackerClient extends I2PThread
|
||||
private final static int SLEEP = 5; // 5 minutes.
|
||||
private final static int DELAY_MIN = 2000; // 2 secs.
|
||||
private final static int DELAY_MUL = 1500; // 1.5 secs.
|
||||
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
|
||||
private final static int INITIAL_SLEEP = 90*1000;
|
||||
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
|
||||
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
|
||||
|
||||
private final MetaInfo meta;
|
||||
private final PeerCoordinator coordinator;
|
||||
@@ -54,8 +58,7 @@ public class TrackerClient extends I2PThread
|
||||
private boolean stop;
|
||||
private boolean started;
|
||||
|
||||
private long interval;
|
||||
private long lastRequestTime;
|
||||
private List trackers;
|
||||
|
||||
public TrackerClient(MetaInfo meta, PeerCoordinator coordinator)
|
||||
{
|
||||
@@ -100,14 +103,47 @@ public class TrackerClient extends I2PThread
|
||||
|
||||
public void run()
|
||||
{
|
||||
// XXX - Support other IPs
|
||||
String announce = meta.getAnnounce(); //I2PSnarkUtil.instance().rewriteAnnounce(meta.getAnnounce());
|
||||
String infoHash = urlencode(meta.getInfoHash());
|
||||
String peerID = urlencode(coordinator.getID());
|
||||
|
||||
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash
|
||||
+ " xmitAnnounce: [" + announce + "]");
|
||||
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
|
||||
|
||||
// Construct the list of trackers for this torrent,
|
||||
// starting with the primary one listed in the metainfo,
|
||||
// followed by the secondary open trackers
|
||||
// It's painful, but try to make sure if an open tracker is also
|
||||
// the primary tracker, that we don't add it twice.
|
||||
trackers = new ArrayList(2);
|
||||
trackers.add(new Tracker(meta.getAnnounce(), true));
|
||||
List tlist = SnarkManager.instance().getOpenTrackers();
|
||||
if (tlist != null) {
|
||||
for (int i = 0; i < tlist.size(); i++) {
|
||||
String url = (String)tlist.get(i);
|
||||
if (!url.startsWith("http://")) {
|
||||
_log.error("Bad announce URL: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
int slash = url.indexOf('/', 7);
|
||||
if (slash <= 7) {
|
||||
_log.error("Bad announce URL: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
if (meta.getAnnounce().startsWith(url.substring(0, slash)))
|
||||
continue;
|
||||
String dest = I2PSnarkUtil.instance().lookup(url.substring(7, slash));
|
||||
if (dest == null) {
|
||||
_log.error("Announce host unknown: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
if (meta.getAnnounce().startsWith("http://" + dest))
|
||||
continue;
|
||||
if (meta.getAnnounce().startsWith("http://i2p/" + dest))
|
||||
continue;
|
||||
trackers.add(new Tracker(url, false));
|
||||
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
|
||||
}
|
||||
}
|
||||
|
||||
long uploaded = coordinator.getUploaded();
|
||||
long downloaded = coordinator.getDownloaded();
|
||||
long left = coordinator.getLeft();
|
||||
@@ -119,78 +155,29 @@ public class TrackerClient extends I2PThread
|
||||
{
|
||||
if (!verifyConnected()) return;
|
||||
boolean started = false;
|
||||
while (!started)
|
||||
{
|
||||
sleptTime = 0;
|
||||
try
|
||||
{
|
||||
// Send start.
|
||||
TrackerInfo info = doRequest(announce, infoHash, peerID,
|
||||
uploaded, downloaded, left,
|
||||
STARTED_EVENT);
|
||||
Set peers = info.getPeers();
|
||||
coordinator.trackerSeenPeers = peers.size();
|
||||
coordinator.trackerProblems = null;
|
||||
if (!completed) {
|
||||
Iterator it = peers.iterator();
|
||||
while (it.hasNext()) {
|
||||
Peer cur = (Peer)it.next();
|
||||
coordinator.addPeer(cur);
|
||||
int delay = DELAY_MUL;
|
||||
delay *= ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
|
||||
delay += DELAY_MIN;
|
||||
sleptTime += delay;
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
started = true;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
// Probably not fatal (if it doesn't last to long...)
|
||||
Snark.debug
|
||||
("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)
|
||||
break;
|
||||
|
||||
if (!started)
|
||||
{
|
||||
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||
try
|
||||
{
|
||||
// Sleep one minutes...
|
||||
Thread.sleep(60*1000);
|
||||
}
|
||||
catch(InterruptedException interrupt)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean firstTime = true;
|
||||
int consecutiveFails = 0;
|
||||
Random r = new Random();
|
||||
while(!stop)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Sleep some minutes...
|
||||
// Sleep the minimum interval for all the trackers, but 60s minimum
|
||||
// except for the first time...
|
||||
int delay;
|
||||
if(coordinator.trackerProblems != null && !completed) {
|
||||
delay = 60*1000;
|
||||
} else if(completed) {
|
||||
delay = 3*SLEEP*60*1000 + r.nextInt(120*1000);
|
||||
} else {
|
||||
delay = SLEEP*60*1000 + r.nextInt(120*1000);
|
||||
delay -= sleptTime;
|
||||
}
|
||||
int random = r.nextInt(120*1000);
|
||||
if (firstTime) {
|
||||
delay = r.nextInt(30*1000);
|
||||
firstTime = false;
|
||||
} else if (completed && started)
|
||||
delay = 3*SLEEP*60*1000 + random;
|
||||
else if (coordinator.trackerProblems != null && ++consecutiveFails < MAX_CONSEC_FAILS)
|
||||
delay = INITIAL_SLEEP;
|
||||
else
|
||||
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
|
||||
delay = SLEEP*60*1000 + random;
|
||||
|
||||
if (delay > 0)
|
||||
Thread.sleep(delay);
|
||||
}
|
||||
@@ -218,21 +205,37 @@ public class TrackerClient extends I2PThread
|
||||
else
|
||||
event = NO_EVENT;
|
||||
|
||||
// *** loop once for each tracker
|
||||
// Only do a request when necessary.
|
||||
sleptTime = 0;
|
||||
if (event == COMPLETED_EVENT
|
||||
|| coordinator.needPeers()
|
||||
|| System.currentTimeMillis() > lastRequestTime + interval)
|
||||
int maxSeenPeers = 0;
|
||||
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
|
||||
Tracker tr = (Tracker)iter.next();
|
||||
if ((!stop) && (!tr.stop) &&
|
||||
(completed || coordinator.needPeers()) &&
|
||||
(event == COMPLETED_EVENT || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
|
||||
{
|
||||
try
|
||||
{
|
||||
TrackerInfo info = doRequest(announce, infoHash, peerID,
|
||||
if (!tr.started)
|
||||
event = STARTED_EVENT;
|
||||
TrackerInfo info = doRequest(tr, infoHash, peerID,
|
||||
uploaded, downloaded, left,
|
||||
event);
|
||||
|
||||
coordinator.trackerProblems = null;
|
||||
tr.trackerProblems = null;
|
||||
tr.registerFails = 0;
|
||||
tr.consecutiveFails = 0;
|
||||
if (tr.isPrimary)
|
||||
consecutiveFails = 0;
|
||||
started = true;
|
||||
tr.started = true;
|
||||
|
||||
Set peers = info.getPeers();
|
||||
coordinator.trackerSeenPeers = peers.size();
|
||||
tr.seenPeers = peers.size();
|
||||
if (coordinator.trackerSeenPeers < tr.seenPeers) // update rising number quickly
|
||||
coordinator.trackerSeenPeers = tr.seenPeers;
|
||||
if ( (left > 0) && (!completed) ) {
|
||||
// we only want to talk to new people if we need things
|
||||
// from them (duh)
|
||||
@@ -257,16 +260,38 @@ public class TrackerClient extends I2PThread
|
||||
// Probably not fatal (if it doesn't last to long...)
|
||||
Snark.debug
|
||||
("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();
|
||||
+ tr.announce + "': " + ioe, Snark.WARNING);
|
||||
tr.trackerProblems = ioe.getMessage();
|
||||
// don't show secondary tracker problems to the user
|
||||
if (tr.isPrimary)
|
||||
coordinator.trackerProblems = tr.trackerProblems;
|
||||
if (tr.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
|
||||
// Give a guy some time to register it if using opentrackers too
|
||||
if (trackers.size() == 1) {
|
||||
stop = true;
|
||||
coordinator.snark.stopTorrent();
|
||||
} else { // hopefully each on the opentrackers list is really open
|
||||
if (tr.registerFails++ > MAX_REGISTER_FAILS)
|
||||
tr.stop = true;
|
||||
}
|
||||
}
|
||||
if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
|
||||
tr.seenPeers = 0;
|
||||
if (tr.interval < LONG_SLEEP)
|
||||
tr.interval = LONG_SLEEP; // slow down
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
|
||||
maxSeenPeers = tr.seenPeers;
|
||||
} // *** end of trackers loop here
|
||||
|
||||
// we could try and total the unique peers but that's too hard for now
|
||||
coordinator.trackerSeenPeers = maxSeenPeers;
|
||||
if (!started)
|
||||
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||
} // *** end of while loop
|
||||
} // try
|
||||
catch (Throwable t)
|
||||
{
|
||||
I2PSnarkUtil.instance().debug("TrackerClient: " + t, Snark.ERROR, t);
|
||||
@@ -277,21 +302,27 @@ public class TrackerClient extends I2PThread
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!verifyConnected()) return;
|
||||
TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded,
|
||||
// try to contact everybody we can
|
||||
// We don't need I2CP connection for eepget
|
||||
// if (!verifyConnected()) return;
|
||||
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
|
||||
Tracker tr = (Tracker)iter.next();
|
||||
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
|
||||
doRequest(tr, infoHash, peerID, uploaded,
|
||||
downloaded, left, STOPPED_EVENT);
|
||||
}
|
||||
}
|
||||
catch(IOException ioe) { /* ignored */ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private TrackerInfo doRequest(String announce, String infoHash,
|
||||
private TrackerInfo doRequest(Tracker tr, String infoHash,
|
||||
String peerID, long uploaded,
|
||||
long downloaded, long left, String event)
|
||||
throws IOException
|
||||
{
|
||||
String s = announce
|
||||
String s = tr.announce
|
||||
+ "?info_hash=" + infoHash
|
||||
+ "&peer_id=" + peerID
|
||||
+ "&port=" + port
|
||||
@@ -300,9 +331,9 @@ public class TrackerClient extends I2PThread
|
||||
+ "&downloaded=" + downloaded
|
||||
+ "&left=" + left
|
||||
+ ((event != NO_EVENT) ? ("&event=" + event) : "");
|
||||
if (Snark.debug >= Snark.INFO)
|
||||
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
||||
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
||||
|
||||
tr.lastRequestTime = System.currentTimeMillis();
|
||||
File fetched = I2PSnarkUtil.instance().get(s);
|
||||
if (fetched == null) {
|
||||
throw new IOException("Error fetching " + s);
|
||||
@@ -315,15 +346,13 @@ public class TrackerClient extends I2PThread
|
||||
|
||||
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
|
||||
coordinator.getMetaInfo());
|
||||
if (Snark.debug >= Snark.INFO)
|
||||
Snark.debug("TrackerClient response: " + info, Snark.INFO);
|
||||
lastRequestTime = System.currentTimeMillis();
|
||||
Snark.debug("TrackerClient response: " + info, Snark.INFO);
|
||||
|
||||
String failure = info.getFailureReason();
|
||||
if (failure != null)
|
||||
throw new IOException(failure);
|
||||
|
||||
interval = info.getInterval() * 1000;
|
||||
tr.interval = info.getInterval() * 1000;
|
||||
return info;
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
@@ -349,4 +378,32 @@ public class TrackerClient extends I2PThread
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private class Tracker
|
||||
{
|
||||
String announce;
|
||||
boolean isPrimary;
|
||||
long interval;
|
||||
long lastRequestTime;
|
||||
String trackerProblems;
|
||||
boolean stop;
|
||||
boolean started;
|
||||
int registerFails;
|
||||
int consecutiveFails;
|
||||
int seenPeers;
|
||||
|
||||
public Tracker(String a, boolean p)
|
||||
{
|
||||
announce = a;
|
||||
isPrimary = p;
|
||||
interval = INITIAL_SLEEP;
|
||||
lastRequestTime = 0;
|
||||
trackerProblems = null;
|
||||
stop = false;
|
||||
started = false;
|
||||
registerFails = 0;
|
||||
consecutiveFails = 0;
|
||||
seenPeers = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -107,13 +107,17 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
if (I2PSnarkUtil.instance().connected())
|
||||
out.write("<a href=\"" + uri + "?action=StopAll&nonce=" + _nonce +
|
||||
"\" title=\"Stop all torrents and the i2p tunnel\">Stop All</a>");
|
||||
else if (snarks.size() > 0)
|
||||
out.write("<a href=\"" + uri + "?action=StartAll&nonce=" + _nonce +
|
||||
"\" title=\"Start all torrents and the i2p tunnel\">Start All</a>");
|
||||
else
|
||||
out.write(" ");
|
||||
out.write("</th></tr></thead>\n");
|
||||
for (int i = 0; i < snarks.size(); i++) {
|
||||
Snark snark = (Snark)snarks.get(i);
|
||||
boolean showPeers = "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
|
||||
displaySnark(out, snark, uri, i, stats, showPeers);
|
||||
boolean showDebug = "2".equals(peerParam);
|
||||
boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
|
||||
displaySnark(out, snark, uri, i, stats, showPeers, showDebug);
|
||||
}
|
||||
if (snarks.size() <= 0) {
|
||||
out.write(TABLE_EMPTY);
|
||||
@@ -248,23 +252,31 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
_manager.addMessage("Torrent file deleted: " + f.getAbsolutePath());
|
||||
List files = snark.meta.getFiles();
|
||||
String dataFile = snark.meta.getName();
|
||||
for (int i = 0; files != null && i < files.size(); i++) {
|
||||
// multifile torrents have the getFiles() return lists of lists of filenames, but
|
||||
// each of those lists just contain a single file afaict...
|
||||
File df = new File(_manager.getDataDir(), files.get(i).toString());
|
||||
boolean deleted = FileUtil.rmdir(df, false);
|
||||
if (deleted)
|
||||
_manager.addMessage("Data dir deleted: " + df.getAbsolutePath());
|
||||
else
|
||||
_manager.addMessage("Data dir could not be deleted: " + df.getAbsolutePath());
|
||||
}
|
||||
if (dataFile != null) {
|
||||
f = new File(_manager.getDataDir(), dataFile);
|
||||
boolean deleted = f.delete();
|
||||
if (deleted)
|
||||
f = new File(_manager.getDataDir(), dataFile);
|
||||
if (files == null) { // single file torrent
|
||||
if (f.delete())
|
||||
_manager.addMessage("Data file deleted: " + f.getAbsolutePath());
|
||||
else
|
||||
_manager.addMessage("Data file could not be deleted: " + f.getAbsolutePath());
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < files.size(); i++) { // pass 1 delete files
|
||||
// multifile torrents have the getFiles() return lists of lists of filenames, but
|
||||
// each of those lists just contain a single file afaict...
|
||||
File df = Storage.getFileFromNames(f, (List) files.get(i));
|
||||
if (df.delete())
|
||||
_manager.addMessage("Data file deleted: " + df.getAbsolutePath());
|
||||
else
|
||||
_manager.addMessage("Data file could not be deleted: " + df.getAbsolutePath());
|
||||
}
|
||||
for (int i = files.size() - 1; i >= 0; i--) { // pass 2 delete dirs - not foolproof,
|
||||
// we could sort and do a strict bottom-up
|
||||
File df = Storage.getFileFromNames(f, (List) files.get(i));
|
||||
df = df.getParentFile();
|
||||
if (df == null || !df.exists())
|
||||
continue;
|
||||
if(df.delete())
|
||||
_manager.addMessage("Data dir deleted: " + df.getAbsolutePath());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -281,7 +293,10 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String i2cpPort = req.getParameter("i2cpPort");
|
||||
String i2cpOpts = req.getParameter("i2cpOpts");
|
||||
String upLimit = req.getParameter("upLimit");
|
||||
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit);
|
||||
String upBW = req.getParameter("upBW");
|
||||
boolean useOpenTrackers = req.getParameter("useOpenTrackers") != null;
|
||||
String openTrackers = req.getParameter("openTrackers");
|
||||
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, upBW, useOpenTrackers, openTrackers);
|
||||
} else if ("Create torrent".equals(action)) {
|
||||
String baseData = req.getParameter("baseFile");
|
||||
if (baseData != null) {
|
||||
@@ -297,16 +312,19 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
try {
|
||||
Storage s = new Storage(baseFile, announceURL, null);
|
||||
s.create();
|
||||
s.close(); // close the files... maybe need a way to pass this Storage to addTorrent rather than starting over
|
||||
MetaInfo info = s.getMetaInfo();
|
||||
File torrentFile = new File(baseFile.getParent(), baseFile.getName() + ".torrent");
|
||||
if (torrentFile.exists())
|
||||
throw new IOException("Cannot overwrite an existing .torrent file: " + torrentFile.getPath());
|
||||
_manager.saveTorrentStatus(info, s.getBitField()); // so addTorrent won't recheck
|
||||
// DirMonitor could grab this first, maybe hold _snarks lock?
|
||||
FileOutputStream out = new FileOutputStream(torrentFile);
|
||||
out.write(info.getTorrentData());
|
||||
out.close();
|
||||
_manager.addMessage("Torrent created for " + baseFile.getName() + ": " + torrentFile.getAbsolutePath());
|
||||
// now fire it up, but don't automatically seed it
|
||||
_manager.addTorrent(torrentFile.getCanonicalPath(), false);
|
||||
_manager.addTorrent(torrentFile.getCanonicalPath(), true);
|
||||
_manager.addMessage("Many I2P trackers require you to register new torrents before seeding - please do so before starting " + baseFile.getName());
|
||||
} catch (IOException ioe) {
|
||||
_manager.addMessage("Error creating a torrent for " + baseFile.getAbsolutePath() + ": " + ioe.getMessage());
|
||||
@@ -327,6 +345,14 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
I2PSnarkUtil.instance().disconnect();
|
||||
_manager.addMessage("I2P tunnel closed");
|
||||
}
|
||||
} else if ("StartAll".equals(action)) {
|
||||
_manager.addMessage("Opening the I2P tunnel and starting all torrents");
|
||||
List snarks = getSortedSnarks(req);
|
||||
for (int i = 0; i < snarks.size(); i++) {
|
||||
Snark snark = (Snark)snarks.get(i);
|
||||
if (snark.stopped)
|
||||
snark.startTorrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +371,7 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
|
||||
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60;
|
||||
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 {
|
||||
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, boolean showDebug) throws IOException {
|
||||
String filename = snark.torrent;
|
||||
File f = new File(filename);
|
||||
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
|
||||
@@ -529,6 +555,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
else
|
||||
client = "Unknown";
|
||||
out.write("<font size=-1>" + client + "</font> <tt>" + peer.toString().substring(5, 9) + "</tt>");
|
||||
if (showDebug)
|
||||
out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td>\n\t");
|
||||
@@ -577,6 +605,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
|
||||
out.write("</td></tr>\n\t");
|
||||
if (showDebug)
|
||||
out.write("<tr><td colspan=\"8\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">" + peer.getSocket() + "</td></tr>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -638,6 +668,8 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
String uri = req.getRequestURI();
|
||||
String dataDir = _manager.getDataDir().getAbsolutePath();
|
||||
boolean autoStart = _manager.shouldAutoStart();
|
||||
boolean useOpenTrackers = _manager.shouldUseOpenTrackers();
|
||||
String openTrackers = _manager.getOpenTrackerString();
|
||||
//int seedPct = 0;
|
||||
|
||||
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
|
||||
@@ -669,17 +701,25 @@ public class I2PSnarkServlet extends HttpServlet {
|
||||
out.write("</select><br />\n");
|
||||
*/
|
||||
out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\""
|
||||
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" /> peers<br />\n");
|
||||
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" maxlength=\"3\" /> peers<br />\n");
|
||||
out.write("Up bandwidth limit: <input type=\"text\" name=\"upBW\" value=\""
|
||||
+ I2PSnarkUtil.instance().getMaxUpBW() + "\" size=\"3\" maxlength=\"3\" /> KBps <i>(Router Up BW / 3 recommended)</i><br />\n");
|
||||
|
||||
out.write("Use open trackers also: <input type=\"checkbox\" name=\"useOpenTrackers\" value=\"true\" "
|
||||
+ (useOpenTrackers ? "checked " : "")
|
||||
+ "title=\"If true, uses open trackers in addition\" /> ");
|
||||
out.write("Announce URLs: <input type=\"text\" name=\"openTrackers\" value=\""
|
||||
+ openTrackers + "\" size=\"50\" /><br />\n");
|
||||
|
||||
//out.write("<hr />\n");
|
||||
out.write("EepProxy host: <input type=\"text\" name=\"eepHost\" value=\""
|
||||
+ I2PSnarkUtil.instance().getEepProxyHost() + "\" size=\"15\" /> ");
|
||||
out.write("port: <input type=\"text\" name=\"eepPort\" value=\""
|
||||
+ I2PSnarkUtil.instance().getEepProxyPort() + "\" size=\"5\" /><br />\n");
|
||||
+ I2PSnarkUtil.instance().getEepProxyPort() + "\" size=\"5\" maxlength=\"5\" /><br />\n");
|
||||
out.write("I2CP host: <input type=\"text\" name=\"i2cpHost\" value=\""
|
||||
+ I2PSnarkUtil.instance().getI2CPHost() + "\" size=\"15\" /> ");
|
||||
out.write("port: <input type=\"text\" name=\"i2cpPort\" value=\"" +
|
||||
+ I2PSnarkUtil.instance().getI2CPPort() + "\" size=\"5\" /> <br />\n");
|
||||
+ I2PSnarkUtil.instance().getI2CPPort() + "\" size=\"5\" maxlength=\"5\" /> <br />\n");
|
||||
StringBuffer opts = new StringBuffer(64);
|
||||
Map options = new TreeMap(I2PSnarkUtil.instance().getI2CPOptions());
|
||||
for (Iterator iter = options.keySet().iterator(); iter.hasNext(); ) {
|
||||
@@ -813,7 +853,8 @@ class FetchAndAdd implements Runnable {
|
||||
}
|
||||
public void run() {
|
||||
_url = _url.trim();
|
||||
File file = I2PSnarkUtil.instance().get(_url, false);
|
||||
// 3 retries
|
||||
File file = I2PSnarkUtil.instance().get(_url, false, 3);
|
||||
try {
|
||||
if ( (file != null) && (file.exists()) && (file.length() > 0) ) {
|
||||
_manager.addMessage("Torrent fetched from " + _url);
|
||||
|
@@ -122,6 +122,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed.<BR>")
|
||||
.getBytes();
|
||||
|
||||
private final static byte[] ERR_LOCALHOST =
|
||||
("HTTP/1.1 403 Access Denied\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
||||
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>")
|
||||
.getBytes();
|
||||
|
||||
private final static int MAX_POSTBYTES = 20*1024*1024; // arbitrary but huge - all in memory, no temp file
|
||||
private final static byte[] ERR_MAXPOST =
|
||||
("HTTP/1.1 503 Bad POST\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
||||
"The maximum POST size is " + MAX_POSTBYTES + " bytes.<BR>")
|
||||
.getBytes();
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
@@ -394,6 +413,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
usingWWWProxy = true;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
|
||||
} else if (host.toLowerCase().startsWith("localhost:")) {
|
||||
if (out != null) {
|
||||
out.write(ERR_LOCALHOST);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
} else {
|
||||
request = request.substring(pos + 1);
|
||||
pos = request.indexOf("/");
|
||||
@@ -484,12 +513,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
|
||||
|
||||
int postbytes = 0;
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i = br.read();
|
||||
if (i != -1) {
|
||||
newRequest.append((char) i);
|
||||
if (++postbytes > MAX_POSTBYTES) {
|
||||
if (out != null) {
|
||||
out.write(ERR_MAXPOST);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method == null || destination == null) {
|
||||
l.log("No HTTP method found in the request.");
|
||||
if (out != null) {
|
||||
@@ -559,6 +601,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
l.log(ex.getMessage());
|
||||
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||
closeSocket(s);
|
||||
} catch (OutOfMemoryError oom) { // mainly for huge POSTs
|
||||
IOException ex = new IOException("OOM (in POST?)");
|
||||
_log.info("getPrefix(requestId) + Error trying to connect", ex);
|
||||
l.log(ex.getMessage());
|
||||
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||
closeSocket(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +645,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private static String jumpServers[] = {"http://orion.i2p/jump/",
|
||||
private static String jumpServers[] = {
|
||||
"http://i2host.i2p/cgi-bin/i2hostjump?",
|
||||
// "http://orion.i2p/jump/",
|
||||
"http://stats.i2p/cgi-bin/jump.cgi?a=",
|
||||
"http://trevorreznik.i2p/cgi-bin/jump.php?hostname="
|
||||
};
|
||||
private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
||||
|
@@ -164,7 +164,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("inbound: "+outmsg);
|
||||
}
|
||||
outmsg=outmsg+"\n";
|
||||
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
|
||||
output.write(outmsg.getBytes("ISO-8859-1"));
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -238,7 +238,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("outbound: "+outmsg);
|
||||
}
|
||||
outmsg=outmsg+"\n";
|
||||
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
|
||||
output.write(outmsg.getBytes("ISO-8859-1"));
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -272,7 +272,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
int idx=0;
|
||||
final String[] allowedCommands =
|
||||
{
|
||||
"NOTICE",
|
||||
// "NOTICE", // can contain CTCP
|
||||
//"PING",
|
||||
//"PONG",
|
||||
"MODE",
|
||||
@@ -306,34 +306,36 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
} catch(NumberFormatException nfe){}
|
||||
|
||||
|
||||
if ("PING".equals(command))
|
||||
if ("PING".equalsIgnoreCase(command))
|
||||
return "PING 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works
|
||||
if ("PONG".equals(command)) {
|
||||
if ("PONG".equalsIgnoreCase(command)) {
|
||||
// Turn the received ":irc.freshcoffee.i2p PONG irc.freshcoffee.i2p :127.0.0.1"
|
||||
// into ":127.0.0.1 PONG 127.0.0.1 " so that the caller can append the client's extra parameter
|
||||
// though, does 127.0.0.1 work for irc clients connecting remotely? and for all of them? sure would
|
||||
// be great if irc clients actually followed the RFCs here, but i guess thats too much to ask.
|
||||
// If we haven't PINGed them, or the PING we sent isn't something we know how to filter, this
|
||||
// is blank.
|
||||
String pong = expectedPong.length() > 0 ? expectedPong.toString() : null;
|
||||
//
|
||||
// String pong = expectedPong.length() > 0 ? expectedPong.toString() : null;
|
||||
// If we aren't going to rewrite it, pass it through
|
||||
String pong = expectedPong.length() > 0 ? expectedPong.toString() : s;
|
||||
expectedPong.setLength(0);
|
||||
return pong;
|
||||
}
|
||||
|
||||
// Allow all allowedCommands
|
||||
for(int i=0;i<allowedCommands.length;i++) {
|
||||
if(allowedCommands[i].equals(command))
|
||||
if(allowedCommands[i].equalsIgnoreCase(command))
|
||||
return s;
|
||||
}
|
||||
|
||||
// Allow PRIVMSG, but block CTCP.
|
||||
if("PRIVMSG".equals(command))
|
||||
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
|
||||
{
|
||||
String msg;
|
||||
msg = field[idx++];
|
||||
|
||||
byte[] bytes = msg.getBytes();
|
||||
if(bytes[1]==0x01)
|
||||
if(msg.indexOf(0x01) >= 0) // CTCP marker ^A can be anywhere, not just immediately after the ':'
|
||||
{
|
||||
// CTCP
|
||||
msg=msg.substring(2);
|
||||
@@ -356,7 +358,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
String command;
|
||||
final String[] allowedCommands =
|
||||
{
|
||||
"NOTICE",
|
||||
// "NOTICE", // can contain CTCP
|
||||
"MODE",
|
||||
"JOIN",
|
||||
"NICK",
|
||||
@@ -387,7 +389,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
command = field[0].toUpperCase();
|
||||
|
||||
if ("PING".equals(command)) {
|
||||
if ("PING".equalsIgnoreCase(command)) {
|
||||
// Most clients just send a PING and are happy with any old PONG. Others,
|
||||
// like BitchX, actually expect certain behavior. It sends two different pings:
|
||||
// "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy)
|
||||
@@ -403,13 +405,15 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
expectedPong.setLength(0);
|
||||
if (field.length == 1) { // PING
|
||||
rv = "PING";
|
||||
expectedPong.append("PONG 127.0.0.1");
|
||||
// If we aren't rewriting the PING don't rewrite the PONG
|
||||
// expectedPong.append("PONG 127.0.0.1");
|
||||
} else if (field.length == 2) { // PING nonce
|
||||
rv = "PING " + field[1];
|
||||
expectedPong.append("PONG ").append(field[1]);
|
||||
// If we aren't rewriting the PING don't rewrite the PONG
|
||||
// expectedPong.append("PONG ").append(field[1]);
|
||||
} else if (field.length == 3) { // PING nonce serverLocation
|
||||
rv = "PING " + field[1];
|
||||
expectedPong.append("PONG ").append(field[1]);
|
||||
expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
|
||||
@@ -417,28 +421,37 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("sending ping " + rv + ", waiting for " + expectedPong + " orig was [" + s + "]");
|
||||
_log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
|
||||
|
||||
return rv;
|
||||
}
|
||||
if ("PONG".equals(command))
|
||||
if ("PONG".equalsIgnoreCase(command))
|
||||
return "PONG 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works
|
||||
|
||||
// Allow all allowedCommands
|
||||
for(int i=0;i<allowedCommands.length;i++)
|
||||
{
|
||||
if(allowedCommands[i].equals(command))
|
||||
if(allowedCommands[i].equalsIgnoreCase(command))
|
||||
return s;
|
||||
}
|
||||
|
||||
// mIRC sends "NOTICE user :DCC Send file (IP)"
|
||||
// in addition to the CTCP version
|
||||
if("NOTICE".equalsIgnoreCase(command))
|
||||
{
|
||||
String msg = field[2];
|
||||
if(msg.startsWith(":DCC "))
|
||||
return null;
|
||||
// fall through
|
||||
}
|
||||
|
||||
// Allow PRIVMSG, but block CTCP (except ACTION).
|
||||
if("PRIVMSG".equals(command))
|
||||
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
|
||||
{
|
||||
String msg;
|
||||
msg = field[2];
|
||||
|
||||
byte[] bytes = msg.getBytes();
|
||||
if(bytes[1]==0x01)
|
||||
if(msg.indexOf(0x01) >= 0) // CTCP marker ^A can be anywhere, not just immediately after the ':'
|
||||
{
|
||||
// CTCP
|
||||
msg=msg.substring(2);
|
||||
@@ -451,14 +464,14 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
return s;
|
||||
}
|
||||
|
||||
if("USER".equals(command)) {
|
||||
if("USER".equalsIgnoreCase(command)) {
|
||||
int idx = field[2].lastIndexOf(":");
|
||||
if(idx<0)
|
||||
return "USER user hostname localhost :realname";
|
||||
String realname = field[2].substring(idx+1);
|
||||
String ret = "USER "+field[1]+" hostname localhost :"+realname;
|
||||
return ret;
|
||||
} else if ("QUIT".equals(command)) {
|
||||
} else if ("QUIT".equalsIgnoreCase(command)) {
|
||||
return "QUIT :leaving";
|
||||
}
|
||||
|
||||
|
@@ -186,8 +186,9 @@
|
||||
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% if (tunnelDepth > 2) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
|
||||
<option value="3"<%=(tunnelDepth == 3 ? " selected=\"selected\"" : "") %>>3 hop tunnel (very high anonymity, poor performance)</option>
|
||||
<% if (tunnelDepth > 3) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel (very poor performance)</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
@@ -213,11 +214,11 @@
|
||||
</label>
|
||||
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
|
||||
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% if (tunnelQuantity > 3) {
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
@@ -228,9 +229,9 @@
|
||||
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
|
||||
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
|
||||
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel each direction (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels each direction (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels each direction (high redundancy, high resource usage)</option>
|
||||
<% if (tunnelBackupQuantity > 3) {
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
|
||||
<% }
|
||||
@@ -284,4 +285,4 @@
|
||||
<div id="pageFooter">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@@ -158,8 +158,9 @@
|
||||
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% if (tunnelDepth > 2) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
|
||||
<option value="3"<%=(tunnelDepth == 3 ? " selected=\"selected\"" : "") %>>3 hop tunnel (very high anonymity, poor performance)</option>
|
||||
<% if (tunnelDepth > 3) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel (very poor performance)</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
@@ -185,11 +186,11 @@
|
||||
</label>
|
||||
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
|
||||
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% if (tunnelQuantity > 3) {
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
@@ -200,9 +201,9 @@
|
||||
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
|
||||
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
|
||||
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel each direction (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels each direction (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels each direction (high redundancy, high resource usage)</option>
|
||||
<% if (tunnelBackupQuantity > 3) {
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
|
||||
<% }
|
||||
@@ -256,4 +257,4 @@
|
||||
<div id="pageFooter">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@@ -1,21 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="jetty">
|
||||
|
||||
|
||||
<property name="jetty.sha1" value="021164f84da7304bd1ff07c268b45aa3e0b13322" />
|
||||
<property name="jetty.md5" value="a61adc832be6baf2678935506743cfc3" />
|
||||
<property name="jetty.url" value="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.12.zip" />
|
||||
<property name="jetty.filename" value="jetty-5.1.12.zip" />
|
||||
|
||||
<target name="all" depends="build" />
|
||||
<target name="fetchJettylib" >
|
||||
<available property="jetty.available" file="jetty-5.1.12.zip" />
|
||||
<ant target="doFetchJettylib" />
|
||||
|
||||
<target name="ensureJettylib" >
|
||||
<available property="jetty.zip.available" file="${jetty.filename}" type="file" />
|
||||
<available property="jetty.zip.extracted" file="jettylib" type="dir" />
|
||||
<ant target="fetchJettylib" />
|
||||
<ant target="verifyJettylib" />
|
||||
<ant target="extractJettylib" />
|
||||
</target>
|
||||
<target name="doFetchJettylib" unless="jetty.available" >
|
||||
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.12" />
|
||||
<echo message="distribution (http://jetty.mortbay.org/). These are not " />
|
||||
<echo message="necessary for using I2P, but are used by some applications on top of I2P," />
|
||||
<echo message="such as the routerconsole." />
|
||||
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.12.zip" verbose="true" dest="jetty-5.1.12.zip" />
|
||||
<ant target="doExtract" />
|
||||
|
||||
<target name="fetchJettylib" unless="jetty.zip.available" >
|
||||
<echo message="It seems that you don't have '${jetty.filename}' deployed." />
|
||||
<echo message="The build script can download this file for you automatically," />
|
||||
<echo message="or alternatively you can obtain it manually from:" />
|
||||
<echo message="${jetty.url}" />
|
||||
<echo message="" />
|
||||
<echo message="The libraries contained in the fetched file provide the Jetty web server" />
|
||||
<echo message="(http://jetty.mortbay.org/). They are not absolutely necessary" />
|
||||
<echo message="but strongly recommended, since they are used by some applications" />
|
||||
<echo message="on top of I2P, like the router console." />
|
||||
<echo message="" />
|
||||
<echo message="Even if you deploy the Jetty archive manually, the build script will" />
|
||||
<echo message="still attempt to verify its checksums, which must be:" />
|
||||
<echo message="SHA1 ${jetty.sha1}" />
|
||||
<echo message="MD5 ${jetty.md5}" />
|
||||
<echo message="" />
|
||||
<input message="Download Jetty archive automatically?" validargs="y,n" addproperty="jetty.download" />
|
||||
<fail message="Aborting as requested. Please deploy the Jetty archive manually." >
|
||||
<condition>
|
||||
<equals arg1="${jetty.download}" arg2="n"/>
|
||||
</condition>
|
||||
</fail>
|
||||
<get src="${jetty.url}" verbose="true" dest="${jetty.filename}" />
|
||||
</target>
|
||||
<target name="doExtract">
|
||||
<unzip src="jetty-5.1.12.zip" dest="." />
|
||||
|
||||
<target name="verifyJettylib" >
|
||||
<condition property="jetty.zip.verified" >
|
||||
<and>
|
||||
<checksum file="${jetty.filename}" algorithm="SHA" property="${jetty.sha1}" />
|
||||
<checksum file="${jetty.filename}" algorithm="MD5" property="${jetty.md5}" />
|
||||
</and>
|
||||
</condition>
|
||||
<fail message="Jetty archive does not match its checksums!" >
|
||||
<condition>
|
||||
<not>
|
||||
<istrue value="${jetty.zip.verified}" />
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
</target>
|
||||
|
||||
<target name="extractJettylib" unless="jetty.zip.extracted" >
|
||||
<unzip src="${jetty.filename}" dest="." />
|
||||
<mkdir dir="jettylib" />
|
||||
<copy todir="jettylib">
|
||||
<fileset dir="jetty-5.1.12/lib">
|
||||
@@ -26,7 +69,7 @@
|
||||
<fileset dir="jetty-5.1.12/ext">
|
||||
<include name="ant.jar" />
|
||||
<include name="commons-el.jar" />
|
||||
<include name="commons-logging.jar" />
|
||||
<include name="commons-logging.jar" />
|
||||
<include name="jasper-compiler.jar" />
|
||||
<include name="jasper-runtime.jar" />
|
||||
<include name="javax.servlet.jar" />
|
||||
@@ -36,7 +79,8 @@
|
||||
</copy>
|
||||
<delete dir="jetty-5.1.12" />
|
||||
</target>
|
||||
<target name="build" depends="fetchJettylib" />
|
||||
|
||||
<target name="build" depends="ensureJettylib" />
|
||||
<target name="builddep" />
|
||||
<target name="compile" />
|
||||
<target name="jar" />
|
||||
|
@@ -138,8 +138,6 @@ public class I2PSocketManagerFactory {
|
||||
I2PSession session = client.createSession(myPrivateKeyStream, opts);
|
||||
session.connect();
|
||||
I2PSocketManager sockMgr = createManager(session, opts, "manager");
|
||||
if (sockMgr != null)
|
||||
sockMgr.setDefaultOptions(sockMgr.buildOptions(opts));
|
||||
return sockMgr;
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("Error creating session for socket manager", ise);
|
||||
@@ -199,4 +197,4 @@ public class I2PSocketManagerFactory {
|
||||
}
|
||||
return i2cpPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -164,7 +164,7 @@ public class ConfigNetHelper {
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "16";
|
||||
return "32";
|
||||
}
|
||||
public String getOutboundRate() {
|
||||
String rate = _context.getProperty(PROP_OUTBOUND_KBPS);
|
||||
@@ -178,7 +178,7 @@ public class ConfigNetHelper {
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "32";
|
||||
return "48";
|
||||
}
|
||||
public String getOutboundBurstRate() {
|
||||
String rate = _context.getProperty(PROP_OUTBOUND_BURST_KBPS);
|
||||
@@ -276,21 +276,21 @@ public class ConfigNetHelper {
|
||||
}
|
||||
|
||||
public int getShareBandwidth() {
|
||||
String irate = _context.getProperty(PROP_INBOUND_KBPS);
|
||||
String orate = _context.getProperty(PROP_OUTBOUND_KBPS);
|
||||
String pctStr = _context.getProperty(PROP_SHARE_PERCENTAGE);
|
||||
String irate = _context.getProperty(PROP_INBOUND_KBPS, "32");
|
||||
String orate = _context.getProperty(PROP_OUTBOUND_KBPS, "16");
|
||||
String pctStr = _context.getProperty(PROP_SHARE_PERCENTAGE, "" + DEFAULT_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;
|
||||
return 12;
|
||||
int pct = Integer.parseInt(pctStr);
|
||||
return (int) (((float) pct) * Math.min(irateKBps, orateKBps) / 100);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,13 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
private String _graphs;
|
||||
private boolean _explicitFilter;
|
||||
private String _explicitFilterValue;
|
||||
private boolean _isFull;
|
||||
|
||||
public ConfigStatsHandler() {
|
||||
super();
|
||||
_stats = new ArrayList();
|
||||
_explicitFilter = false;
|
||||
_isFull = false;
|
||||
}
|
||||
|
||||
protected void processForm() {
|
||||
@@ -70,6 +72,7 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
|
||||
public void setExplicitFilter(String foo) { _explicitFilter = true; }
|
||||
public void setExplicitFilterValue(String filter) { _explicitFilterValue = filter; }
|
||||
public void setIsFull(String foo) { _isFull = true; }
|
||||
|
||||
/**
|
||||
* The user made changes to the config and wants to save them, so
|
||||
@@ -109,6 +112,7 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
|
||||
_context.router().setConfigSetting(StatManager.PROP_STAT_FILTER, stats.toString());
|
||||
_context.router().setConfigSetting("stat.summaries", _graphs);
|
||||
_context.router().setConfigSetting(StatManager.PROP_STAT_FULL, "" + _isFull);
|
||||
boolean ok = _context.router().saveConfig();
|
||||
if (ok)
|
||||
addFormNotice("Stat filter and location updated successfully to: " + stats.toString());
|
||||
|
@@ -10,6 +10,7 @@ import java.util.StringTokenizer;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.stat.FrequencyStat;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -141,4 +142,10 @@ public class ConfigStatsHelper {
|
||||
public boolean getCurrentIsGraphed() { return _currentIsGraphed; }
|
||||
public boolean getCurrentCanBeGraphed() { return _currentCanBeGraphed; }
|
||||
public String getExplicitFilter() { return _filter; }
|
||||
public boolean getIsFull() {
|
||||
String f = _context.getProperty(StatManager.PROP_STAT_FULL);
|
||||
if (f != null && f.equals("true"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.router.web;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerTask;
|
||||
import net.i2p.util.Log;
|
||||
@@ -20,20 +21,29 @@ public class ConfigUpdateHandler extends FormHandler {
|
||||
private String _trustedKeys;
|
||||
|
||||
public static final String PROP_NEWS_URL = "router.newsURL";
|
||||
public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
|
||||
// public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
|
||||
public static final String DEFAULT_NEWS_URL = "http://complication.i2p/news.xml";
|
||||
public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
|
||||
public static final String DEFAULT_REFRESH_FREQUENCY = 12*60*60*1000 + "";
|
||||
public static final String PROP_UPDATE_URL = "router.updateURL";
|
||||
public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud";
|
||||
public static final String PROP_UPDATE_POLICY = "router.updatePolicy";
|
||||
public static final String DEFAULT_UPDATE_POLICY = "notify";
|
||||
public static final String PROP_SHOULD_PROXY = "router.updateThroughProxy";
|
||||
public static final String DEFAULT_SHOULD_PROXY = Boolean.FALSE.toString();
|
||||
public static final String DEFAULT_SHOULD_PROXY = Boolean.TRUE.toString();
|
||||
public static final String PROP_PROXY_HOST = "router.updateProxyHost";
|
||||
public static final String DEFAULT_PROXY_HOST = "localhost";
|
||||
public static final String PROP_PROXY_PORT = "router.updateProxyPort";
|
||||
public static final String DEFAULT_PROXY_PORT = "4444";
|
||||
|
||||
public static final String PROP_UPDATE_URL = "router.updateURL";
|
||||
// public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud";
|
||||
public static final String DEFAULT_UPDATE_URL =
|
||||
"http://amiga.i2p/i2p/i2pupdate.sud\r\n" +
|
||||
"http://stats.i2p/i2p/i2pupdate.sud\r\n" +
|
||||
"http://complication.i2p/i2p/i2pupdate.sud";
|
||||
|
||||
public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys";
|
||||
|
||||
|
||||
protected void processForm() {
|
||||
if ("Check for update now".equals(_action)) {
|
||||
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
|
||||
@@ -52,14 +62,6 @@ public class ConfigUpdateHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
|
||||
String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
|
||||
if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
|
||||
_context.router().setConfigSetting(PROP_UPDATE_URL, _updateURL);
|
||||
addFormNotice("Updating update URL to " + _updateURL);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_proxyHost != null) && (_proxyHost.length() > 0) ) {
|
||||
String oldHost = _context.router().getConfigSetting(PROP_PROXY_HOST);
|
||||
if ( (oldHost == null) || (!_proxyHost.equals(oldHost)) ) {
|
||||
@@ -98,8 +100,22 @@ public class ConfigUpdateHandler extends FormHandler {
|
||||
addFormNotice("Updating update policy to " + _updatePolicy);
|
||||
}
|
||||
}
|
||||
|
||||
// should save the keys...
|
||||
|
||||
if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
|
||||
String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
|
||||
if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
|
||||
_context.router().setConfigSetting(PROP_UPDATE_URL, _updateURL);
|
||||
addFormNotice("Updating update URLs.");
|
||||
}
|
||||
}
|
||||
|
||||
if ( (_trustedKeys != null) && (_trustedKeys.length() > 0) ) {
|
||||
String oldKeys = new TrustedUpdate(_context).getTrustedKeysString();
|
||||
if ( (oldKeys == null) || (!_trustedKeys.equals(oldKeys)) ) {
|
||||
_context.router().setConfigSetting(PROP_TRUSTED_KEYS, _trustedKeys);
|
||||
addFormNotice("Updating trusted keys.");
|
||||
}
|
||||
}
|
||||
|
||||
_context.router().saveConfig();
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.List;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -113,11 +112,6 @@ public class ConfigUpdateHelper {
|
||||
}
|
||||
|
||||
public String getTrustedKeys() {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
List keys = up.getTrustedKeys();
|
||||
for (int i = 0; i < keys.size(); i++)
|
||||
buf.append((String)keys.get(i)).append('\n');
|
||||
return buf.toString();
|
||||
return new TrustedUpdate(_context).getTrustedKeysString();
|
||||
}
|
||||
}
|
||||
|
@@ -70,19 +70,32 @@ public class GraphHelper {
|
||||
}
|
||||
|
||||
if (hasTx && hasRx && !_showEvents)
|
||||
_out.write("<a href=\"viewstat.jsp?stat=bw.combined"
|
||||
+ "&periodCount=" + (3 * _periodCount )
|
||||
+ "&width=" + (3 * _width)
|
||||
+ "&height=" + (3 * _height)
|
||||
+ "\" />");
|
||||
_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");
|
||||
+ "\" title=\"Combined bandwidth graph\" /></a>\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 width=\""
|
||||
_out.write("<a href=\"viewstat.jsp?stat="
|
||||
+ r.getRateStat().getName()
|
||||
+ "&showEvents=" + _showEvents
|
||||
+ "&period=" + r.getPeriod()
|
||||
+ "&periodCount=" + (3 * _periodCount)
|
||||
+ "&width=" + (3 * _width)
|
||||
+ "&height=" + (3 * _height)
|
||||
+ "\" />");
|
||||
_out.write("<img border=\"0\" width=\""
|
||||
+ (_width + 83) + "\" height=\"" + (_height + 92)
|
||||
+ "\" src=\"viewstat.jsp?stat="
|
||||
+ r.getRateStat().getName()
|
||||
@@ -91,7 +104,7 @@ public class GraphHelper {
|
||||
+ "&periodCount=" + _periodCount
|
||||
+ "&width=" + _width
|
||||
+ "&height=" + _height
|
||||
+ "\" title=\"" + title + "\" />\n");
|
||||
+ "\" title=\"" + title + "\" /></a>\n");
|
||||
}
|
||||
if (_refreshDelaySeconds > 0)
|
||||
_out.write("<meta http-equiv=\"refresh\" content=\"" + _refreshDelaySeconds + "\" />\n");
|
||||
|
@@ -24,6 +24,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
private Log _log;
|
||||
private boolean _updateAvailable;
|
||||
private long _lastFetch;
|
||||
private String _lastModified;
|
||||
private static NewsFetcher _instance;
|
||||
//public static final synchronized NewsFetcher getInstance() { return _instance; }
|
||||
public static final synchronized NewsFetcher getInstance(I2PAppContext ctx) {
|
||||
@@ -40,14 +41,16 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(NewsFetcher.class);
|
||||
_instance = this;
|
||||
_lastFetch = 0;
|
||||
updateLastFetched();
|
||||
}
|
||||
|
||||
private void updateLastFetched() {
|
||||
File news = new File(NEWS_FILE);
|
||||
if (news.exists())
|
||||
_lastFetch = news.lastModified();
|
||||
else
|
||||
if (news.exists()) {
|
||||
if (_lastFetch == 0)
|
||||
_lastFetch = news.lastModified();
|
||||
} else
|
||||
_lastFetch = 0;
|
||||
}
|
||||
|
||||
@@ -105,16 +108,15 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
proxyPort = Integer.parseInt(port);
|
||||
EepGet get = null;
|
||||
if (shouldProxy)
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 10, TEMP_NEWS_FILE, newsURL);
|
||||
get = new EepGet(_context, true, proxyHost, proxyPort, 2, TEMP_NEWS_FILE, newsURL, true, null, _lastModified);
|
||||
else
|
||||
get = new EepGet(_context, 10, TEMP_NEWS_FILE, newsURL);
|
||||
get = new EepGet(_context, false, null, 0, 0, TEMP_NEWS_FILE, newsURL, true, null, _lastModified);
|
||||
get.addStatusListener(this);
|
||||
get.fetch();
|
||||
if (get.fetch())
|
||||
_lastModified = get.getLastModified();
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error fetching the news", t);
|
||||
}
|
||||
|
||||
_lastFetch = _context.clock().now();
|
||||
}
|
||||
|
||||
private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\"";
|
||||
@@ -207,22 +209,24 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
boolean copied = FileUtil.copy(TEMP_NEWS_FILE, NEWS_FILE, true);
|
||||
if (copied) {
|
||||
temp.delete();
|
||||
checkForUpdates();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed to copy the news file!");
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Transfer complete, but no file?");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Transfer complete, but no file? - probably 304 Not Modified");
|
||||
}
|
||||
checkForUpdates();
|
||||
_lastFetch = _context.clock().now();
|
||||
}
|
||||
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed to fetch the news from " + url);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Failed to fetch the news from " + url);
|
||||
File temp = new File(TEMP_NEWS_FILE);
|
||||
temp.delete();
|
||||
}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
public void attempting(String url) {}
|
||||
}
|
||||
|
@@ -7,9 +7,13 @@ import java.io.OutputStream;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -18,8 +22,8 @@ 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 I2P configuration property "i2p.reseedURL" is
|
||||
* Handler to deal with reseed requests. This will reseed from the URL
|
||||
* http://i2pdb.tin0.de/netDb/ unless the I2P configuration property "i2p.reseedURL" is
|
||||
* set. It always writes to ./netDb/, so don't mess with that.
|
||||
*
|
||||
*/
|
||||
@@ -31,7 +35,7 @@ public class ReseedHandler {
|
||||
// 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/";
|
||||
private static final String DEFAULT_SEED_URL = "http://i2pdb.tin0.de/netDb/,http://netdb.i2p2.de/";
|
||||
|
||||
public ReseedHandler() {
|
||||
this(ContextHelper.getContext(null));
|
||||
@@ -107,6 +111,7 @@ public class ReseedHandler {
|
||||
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) {}
|
||||
public void attempting(String url) {}
|
||||
// End of EepGet status listeners
|
||||
|
||||
/**
|
||||
@@ -115,11 +120,33 @@ public class ReseedHandler {
|
||||
* save them into this router's netDb dir.
|
||||
*
|
||||
*/
|
||||
private static final String RESEED_TIPS =
|
||||
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
|
||||
"and if nothing helps, read FAQ about reseeding manually.";
|
||||
|
||||
private void reseed(boolean echoStatus) {
|
||||
List URLList = new ArrayList();
|
||||
String URLs = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
StringTokenizer tok = new StringTokenizer(URLs, " ,");
|
||||
while (tok.hasMoreTokens())
|
||||
URLList.add(tok.nextToken().trim());
|
||||
Collections.shuffle(URLList);
|
||||
for (int i = 0; i < URLList.size() && _isRunning; i++)
|
||||
reseedOne((String) URLList.get(i), echoStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a directory listing and then all the routerInfo files in the listing.
|
||||
* The listing must contain (exactly) strings that match:
|
||||
* href="routerInfo-{hash}.dat">
|
||||
* and then it fetches the files
|
||||
* {seedURL}routerInfo-{hash}.dat
|
||||
* after appending a '/' to seedURL if it doesn't have one.
|
||||
* Essentially this means that the seedURL must be a directory, it
|
||||
* can't end with 'index.html', for example.
|
||||
**/
|
||||
private void reseedOne(String seedURL, 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.");
|
||||
@@ -128,8 +155,7 @@ public class ReseedHandler {
|
||||
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.");
|
||||
RESEED_TIPS);
|
||||
// Logging deprecated here since attemptFailed() provides better info
|
||||
_log.debug("Failed reading seed URL: " + seedURL);
|
||||
return;
|
||||
@@ -151,8 +177,7 @@ public class ReseedHandler {
|
||||
_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.");
|
||||
RESEED_TIPS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,17 +201,28 @@ public class ReseedHandler {
|
||||
}
|
||||
}
|
||||
if (echoStatus) System.out.println();
|
||||
if (errors > 0) {
|
||||
|
||||
int failPercent = 100 * errors / urls.size();
|
||||
|
||||
// Less than 10% of failures is considered success,
|
||||
// because some routerInfos will always fail.
|
||||
if ((failPercent >= 10) && (failPercent < 90)) {
|
||||
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.");
|
||||
"Last reseed failed partly (" + failPercent + "% of " + urls.size() + "). " +
|
||||
RESEED_TIPS);
|
||||
}
|
||||
if (failPercent >= 90) {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
|
||||
"Last reseed failed (" + failPercent + "% of " + urls.size() + "). " +
|
||||
RESEED_TIPS);
|
||||
}
|
||||
// Don't go on to the next URL if we have enough
|
||||
if (fetched > 25)
|
||||
_isRunning = false;
|
||||
} 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.");
|
||||
RESEED_TIPS);
|
||||
_log.error("Error reseeding", t);
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,9 @@ package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
@@ -30,6 +33,7 @@ public class UpdateHandler {
|
||||
private DecimalFormat _pct = new DecimalFormat("00.0%");
|
||||
|
||||
private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
|
||||
private static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress";
|
||||
|
||||
public UpdateHandler() {
|
||||
this(ContextHelper.getContext(null));
|
||||
@@ -64,21 +68,27 @@ public class UpdateHandler {
|
||||
}
|
||||
|
||||
public void update() {
|
||||
// don't block waiting for the other one to finish
|
||||
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) {
|
||||
_log.error("Update already running");
|
||||
return;
|
||||
}
|
||||
synchronized (UpdateHandler.class) {
|
||||
if (_updateRunner == null)
|
||||
_updateRunner = new UpdateRunner();
|
||||
if (_updateRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true");
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
|
||||
I2PThread update = new I2PThread(_updateRunner, "Update");
|
||||
update.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
if (_updateRunner == null)
|
||||
return "";
|
||||
return _updateRunner.getStatus();
|
||||
}
|
||||
|
||||
@@ -86,23 +96,24 @@ public class UpdateHandler {
|
||||
private boolean _isRunning;
|
||||
private String _status;
|
||||
private long _startedOn;
|
||||
private long _written;
|
||||
public UpdateRunner() {
|
||||
_isRunning = false;
|
||||
_status = "<b>Updating</b><br />";
|
||||
_status = "<b>Updating</b>";
|
||||
}
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
public String getStatus() { return _status; }
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
update();
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
private void update() {
|
||||
_startedOn = -1;
|
||||
_status = "<b>Updating</b><br />";
|
||||
String updateURL = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
|
||||
_status = "<b>Updating</b>";
|
||||
String updateURL = selectUpdateURL();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Selected update URL: " + updateURL);
|
||||
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
|
||||
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
|
||||
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
|
||||
@@ -110,69 +121,89 @@ public class UpdateHandler {
|
||||
try {
|
||||
proxyPort = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EepGet get = null;
|
||||
if (shouldProxy)
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 10, SIGNED_UPDATE_FILE, updateURL, false);
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 20, SIGNED_UPDATE_FILE, updateURL, false);
|
||||
else
|
||||
get = new EepGet(_context, 10, SIGNED_UPDATE_FILE, updateURL, false);
|
||||
get = new EepGet(_context, 1, SIGNED_UPDATE_FILE, updateURL, false);
|
||||
get.addStatusListener(UpdateRunner.this);
|
||||
_startedOn = _context.clock().now();
|
||||
get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
}
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Attempt failed on " + url, cause);
|
||||
_written = 0;
|
||||
// ignored
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
_written += currentWrite;
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append("<b>Updating</b> ");
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
double pct = ((double)alreadyTransferred + (double)currentWrite) /
|
||||
((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
}
|
||||
buf.append(":<br />\n").append(_written+alreadyTransferred);
|
||||
buf.append(" transferred<br />");
|
||||
buf.append(":<br />\n" + (currentWrite + alreadyTransferred));
|
||||
buf.append(" transferred");
|
||||
_status = buf.toString();
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
_status = "<b>Update downloaded</b><br />";
|
||||
_status = "<b>Update downloaded</b>";
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
boolean ok = up.migrateVerified(RouterVersion.VERSION, SIGNED_UPDATE_FILE, "i2pupdate.zip");
|
||||
File f = new File(SIGNED_UPDATE_FILE);
|
||||
f.delete();
|
||||
if (ok) {
|
||||
_log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
|
||||
_status = "<b>Update verified</b><br />Restarting<br />";
|
||||
_status = "<b>Update verified</b><br />Restarting";
|
||||
restart();
|
||||
} else {
|
||||
_log.log(Log.CRIT, "Update was INVALID - have you changed your keys?");
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
// One other possibility, the version in the file is not sufficient
|
||||
// Perhaps need an int return code - but version problem unlikely?
|
||||
_log.log(Log.CRIT, "Update was INVALID - signing key is not trusted or file is corrupt from " + url);
|
||||
_status = "<b>Update signing key invalid or file is corrupt from " + url + "</b>";
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_log.log(Log.CRIT, "Update did not download completely (" + bytesTransferred + " with "
|
||||
_log.log(Log.CRIT, "Update from " + url + " did not download completely (" + bytesTransferred + " with "
|
||||
+ bytesRemaining + " after " + currentAttempt + " tries)");
|
||||
|
||||
_status = "<b>Transfer failed</b><br />";
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
_status = "<b>Transfer failed</b>";
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
public void attempting(String url) {}
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
_context.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
|
||||
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
|
||||
}
|
||||
|
||||
private String selectUpdateURL() {
|
||||
String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
|
||||
StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
|
||||
List URLList = new ArrayList();
|
||||
while (tok.hasMoreTokens())
|
||||
URLList.add(tok.nextToken().trim());
|
||||
int size = URLList.size();
|
||||
_log.log(Log.DEBUG, "Picking update source from " + size + " candidates.");
|
||||
if (size <= 0) {
|
||||
_log.log(Log.WARN, "Update list is empty - no update available");
|
||||
return null;
|
||||
}
|
||||
int index = I2PAppContext.getGlobalContext().random().nextInt(size);
|
||||
_log.log(Log.DEBUG, "Picked update source " + index + ".");
|
||||
return (String) URLList.get(index);
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,8 @@
|
||||
<input name="outboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundBurstRate" />" /> KBps for
|
||||
<jsp:getProperty name="nethelper" property="outboundBurstFactorBox" /><br />
|
||||
<i>KBps = kilobytes per second = 1024 bytes per second.<br />
|
||||
A negative rate means a default limit of 16KBytes per second.</i><br />
|
||||
A negative inbound rate means a default limit of 32KBytes per second.
|
||||
A negative outbound rate means a default limit of 16KBytes per second.</i><br />
|
||||
Bandwidth share percentage:
|
||||
<jsp:getProperty name="nethelper" property="sharePercentageBox" /><br />
|
||||
<% int share = nethelper.getShareBandwidth();
|
||||
|
@@ -73,6 +73,10 @@ function toggleAll(category)
|
||||
System.setProperty("net.i2p.router.web.ConfigStatsHandler.nonce", new java.util.Random().nextLong()+""); %>
|
||||
<input type="hidden" name="action" value="foo" />
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigStatsHandler.nonce")%>" />
|
||||
Enable full stats?
|
||||
<input type="checkbox" name="isFull" value="true" <%
|
||||
if (statshelper.getIsFull()) { %>checked="true" <% } %>/>
|
||||
(change requires restart to take effect)<br />
|
||||
Stat file: <input type="text" name="filename" value="<%=statshelper.getFilename()%>" /><br />
|
||||
Filter: (<a href="javascript: void(null);" onclick="toggleAll('*')">toggle all</a>)<br />
|
||||
<table>
|
||||
|
@@ -27,22 +27,26 @@
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev);
|
||||
System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %>
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce")%>" />
|
||||
<% if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) { %>
|
||||
<i>Update In Progress</i><br /><br />
|
||||
<% } else { %>
|
||||
<input type="submit" name="action" value="Check for update now" /><br /><br />
|
||||
<% } %>
|
||||
News URL:
|
||||
<input type="text" size="60" name="newsURL" value="<jsp:getProperty name="updatehelper" property="newsURL" />"><br />
|
||||
Refresh frequency:
|
||||
<jsp:getProperty name="updatehelper" property="refreshFrequencySelectBox" /><br />
|
||||
Update URL:
|
||||
<input type="text" size="60" name="updateURL" value="<jsp:getProperty name="updatehelper" property="updateURL" />"><br />
|
||||
Update policy:
|
||||
<jsp:getProperty name="updatehelper" property="updatePolicySelectBox" /><br />
|
||||
Update through the eepProxy?
|
||||
<p>Update through the eepProxy?
|
||||
<jsp:getProperty name="updatehelper" property="updateThroughProxy" /><br />
|
||||
eepProxy host: <input type="text" size="10" name="proxyHost" value="<jsp:getProperty name="updatehelper" property="proxyHost" />" /><br />
|
||||
eepProxy port: <input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /><br />
|
||||
<!-- prompt for the eepproxy -->
|
||||
Trusted keys:
|
||||
<textarea name="trustedKeys" disabled="true" cols="60" rows="2"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea>
|
||||
eepProxy port: <input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /></p>
|
||||
<p>Update URLs:<br />
|
||||
<textarea name="updateURL" cols="90" rows="4"><jsp:getProperty name="updatehelper" property="updateURL" /></textarea></p>
|
||||
<p>Trusted keys:</br />
|
||||
<textarea name="trustedKeys" cols="90" rows="4"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></p>
|
||||
<br />
|
||||
<input type="submit" name="action" value="Save" />
|
||||
</form>
|
||||
</div>
|
||||
|
@@ -34,7 +34,7 @@ Their XML parser requires the Sun XML APIs (JAXP) which is included in binary fo
|
||||
by their binary code license. This product includes software developed by the Apache Software Foundation
|
||||
(http://www.apache.org/). </p>
|
||||
|
||||
<p>Another application you can see on this webpage is <a href="http://www.i2p.net/i2ptunnel">I2PTunnel</a>
|
||||
<p>Another application you can see on this webpage is <a href="http://www.i2p2.i2p/i2ptunnel">I2PTunnel</a>
|
||||
(your <a href="i2ptunnel/" target="_blank">web interface</a>) - a GPL'ed application written by mihi that
|
||||
lets you tunnel normal TCP/IP traffic over I2P (such as the eepproxy and the irc proxy). There is also a
|
||||
<a href="http://susi.i2p/">susimail</a> web based mail client <a href="susimail/susimail">available</a> on
|
||||
@@ -42,14 +42,14 @@ the console, which is a GPL'ed application written by susi23. The addressbook a
|
||||
<a href="http://ragnarok.i2p/">Ragnarok</a> helps maintain your hosts.txt files (see ./addressbook/ for
|
||||
more information).</p>
|
||||
|
||||
<p>The router by default also includes human's public domain <a href="http://www.i2p.net/sam">SAM</a> bridge,
|
||||
<p>The router by default also includes human's public domain <a href="http://www.i2p2.i2p/sam">SAM</a> bridge,
|
||||
which other client applications (such the <a href="http://duck.i2p/i2p-bt/">bittorrent port</a>) can use.
|
||||
There is also an optimized library for doing large number calculations - jbigi - which in turn uses the
|
||||
LGPL licensed <a href="http://swox.com/gmp/">GMP</a> library, tuned for various PC architectures. Launchers for windows users are built with <a href="http://launch4j.sourceforge.net/">Launch4J</a>, and the installer is built with <a href="http://www.izforge.com/izpack/">IzPack</a>. For
|
||||
details on other applications available, as well as their licenses, please see the
|
||||
<a href="http://www.i2p.net/licenses">license policy</a>. Source for the I2P code and most bundled
|
||||
client applications can be found on our <a href="http://www.i2p.net/download">download page</a>, and is
|
||||
in <a href="http://www.i2p.net/cvs">cvs</a>.</p>
|
||||
<a href="http://www.i2p2.i2p/licenses">license policy</a>. Source for the I2P code and most bundled
|
||||
client applications can be found on our <a href="http://www.i2p2.i2p/download">download page</a>.
|
||||
.</p>
|
||||
|
||||
<h2>Release history</h2>
|
||||
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="contenthelper" scope="request" />
|
||||
@@ -59,9 +59,8 @@ in <a href="http://www.i2p.net/cvs">cvs</a>.</p>
|
||||
<jsp:getProperty name="contenthelper" property="textContent" />
|
||||
|
||||
<p>
|
||||
A more complete list of updates can be found
|
||||
<a href="http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/history.txt?rev=HEAD">online</a>
|
||||
(<a href="http://dev.i2p/cgi-bin/cvsweb.cgi/i2p/history.txt?rev=HEAD">anonymously</a>)
|
||||
A more complete list of changes can be found
|
||||
in the history.txt file in your i2p directory.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@@ -16,8 +16,9 @@
|
||||
<b>Now:</b> <jsp:getProperty name="helper" property="time" /><!--<br />
|
||||
<b>Status:</b> <a href="config.jsp"><jsp:getProperty name="helper" property="reachability" /></a>--><%
|
||||
if (helper.updateAvailable()) {
|
||||
// display all the time so we display the final failure message
|
||||
out.print("<br />" + update.getStatus());
|
||||
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) {
|
||||
out.print("<br />" + update.getStatus());
|
||||
} else {
|
||||
long nonce = new java.util.Random().nextLong();
|
||||
String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce");
|
||||
@@ -39,7 +40,7 @@
|
||||
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" />/<jsp:getProperty name="helper" property="activeProfiles" /><br />
|
||||
<b>Fast:</b> <jsp:getProperty name="helper" property="fastPeers" /><br />
|
||||
<b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
|
||||
<!-- <b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br /> -->
|
||||
<b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
|
||||
<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 /><%
|
||||
|
@@ -112,12 +112,15 @@ public class SAMHandlerFactory {
|
||||
case 1:
|
||||
handler = new SAMv1Handler(s, verMajor, verMinor, i2cpProps);
|
||||
break;
|
||||
case 2:
|
||||
handler = new SAMv2Handler(s, verMajor, verMinor, i2cpProps);
|
||||
break;
|
||||
default:
|
||||
_log.error("BUG! Trying to initialize the wrong SAM version!");
|
||||
throw new SAMException("BUG! (in handler instantiation)");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
_log.error("Error creating the v1 handler", e);
|
||||
_log.error("Error creating the handler for version "+verMajor, e);
|
||||
throw new SAMException("IOException caught during SAM handler instantiation");
|
||||
}
|
||||
return handler;
|
||||
@@ -133,15 +136,16 @@ public class SAMHandlerFactory {
|
||||
|| (maxMajor == -1) || (maxMinor == -1)) {
|
||||
return null;
|
||||
}
|
||||
if (minMajor > maxMajor) {
|
||||
return null;
|
||||
} else if ((minMajor == maxMajor) && (minMinor > maxMinor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((minMajor >= 1) && (minMinor >= 0)) {
|
||||
return "1.0";
|
||||
}
|
||||
if ((minMinor >= 10) || (maxMinor >= 10)) return null ;
|
||||
|
||||
float fminVer = (float) minMajor + (float) minMinor / 10 ;
|
||||
float fmaxVer = (float) maxMajor + (float) maxMinor / 10 ;
|
||||
|
||||
|
||||
if ( ( fminVer <= 2.0 ) && ( fmaxVer >= 2.0 ) ) return "2.0" ;
|
||||
|
||||
if ( ( fminVer <= 1.0 ) && ( fmaxVer >= 1.0 ) ) return "1.0" ;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@@ -15,14 +15,31 @@ import net.i2p.data.Destination;
|
||||
/**
|
||||
* Interface for sending streaming data to a SAM client
|
||||
*/
|
||||
|
||||
public interface SAMStreamReceiver {
|
||||
/**
|
||||
* Sends the result of a stream send operation
|
||||
*/
|
||||
public void streamSendAnswer( int id, String result, String bufferState ) throws IOException;
|
||||
|
||||
/**
|
||||
* Notifies that the outwards buffer is free for writing
|
||||
*/
|
||||
public void notifyStreamSendBufferFree( int id ) throws IOException;
|
||||
|
||||
/**
|
||||
* Notify about a new incoming connection
|
||||
*
|
||||
* @param id New connection id
|
||||
*/
|
||||
public void notifyStreamConnection(int id, Destination dest) throws IOException;
|
||||
public void notifyStreamIncomingConnection ( int id, Destination dest ) throws IOException;
|
||||
|
||||
/**
|
||||
* Notify about a new outgoing connection
|
||||
*
|
||||
* @param id New connection id
|
||||
*/
|
||||
public void notifyStreamOutgoingConnection(int id, String result, String msg) throws IOException;
|
||||
|
||||
/**
|
||||
* Send a byte array to a SAM client.
|
||||
|
@@ -47,13 +47,13 @@ public class SAMStreamSession {
|
||||
|
||||
private final static Log _log = new Log(SAMStreamSession.class);
|
||||
|
||||
private final static int SOCKET_HANDLER_BUF_SIZE = 32768;
|
||||
protected final static int SOCKET_HANDLER_BUF_SIZE = 32768;
|
||||
|
||||
private SAMStreamReceiver recv = null;
|
||||
protected SAMStreamReceiver recv = null;
|
||||
|
||||
private SAMStreamSessionServer server = null;
|
||||
|
||||
private I2PSocketManager socketMgr = null;
|
||||
protected I2PSocketManager socketMgr = null;
|
||||
|
||||
private Object handlersMapLock = new Object();
|
||||
/** stream id (Long) to SAMStreamSessionSocketReader */
|
||||
@@ -65,13 +65,14 @@ public class SAMStreamSession {
|
||||
private int lastNegativeId = 0;
|
||||
|
||||
// Can we create outgoing connections?
|
||||
private boolean canCreate = false;
|
||||
protected boolean canCreate = false;
|
||||
|
||||
/**
|
||||
* should we flush every time we get a STREAM SEND, or leave that up to
|
||||
* the streaming lib to decide?
|
||||
*/
|
||||
private boolean forceFlush = false;
|
||||
protected boolean forceFlush = false;
|
||||
|
||||
public static String PROP_FORCE_FLUSH = "sam.forceFlush";
|
||||
public static String DEFAULT_FORCE_FLUSH = "false";
|
||||
|
||||
@@ -189,7 +190,7 @@ public class SAMStreamSession {
|
||||
* @throws InterruptedIOException if the connection timeouts
|
||||
* @throws I2PException if there's another I2P-related error
|
||||
*/
|
||||
public boolean connect(int id, String dest, Properties props) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, SAMInvalidDirectionException {
|
||||
public boolean connect ( int id, String dest, Properties props ) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, SAMInvalidDirectionException, IOException {
|
||||
if (!canCreate) {
|
||||
_log.debug("Trying to create an outgoing connection using a receive-only session");
|
||||
throw new SAMInvalidDirectionException("Trying to create connections through a receive-only session");
|
||||
@@ -208,10 +209,15 @@ public class SAMStreamSession {
|
||||
opts.setConnectTimeout(60 * 1000);
|
||||
|
||||
_log.debug("Connecting new I2PSocket...");
|
||||
|
||||
// blocking connection (SAMv1)
|
||||
|
||||
I2PSocket i2ps = socketMgr.connect(d, opts);
|
||||
|
||||
createSocketHandler(i2ps, id);
|
||||
|
||||
recv.notifyStreamOutgoingConnection ( id, "OK", null );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -277,7 +283,7 @@ public class SAMStreamSession {
|
||||
*
|
||||
* @return An id associated to the socket handler
|
||||
*/
|
||||
private int createSocketHandler(I2PSocket s, int id) {
|
||||
protected int createSocketHandler ( I2PSocket s, int id ) {
|
||||
SAMStreamSessionSocketReader reader = null;
|
||||
StreamSender sender = null;
|
||||
if (id == 0) {
|
||||
@@ -285,8 +291,8 @@ public class SAMStreamSession {
|
||||
}
|
||||
|
||||
try {
|
||||
reader = new SAMStreamSessionSocketReader(s, id);
|
||||
sender = new StreamSender(s, id);
|
||||
reader = newSAMStreamSessionSocketReader(s, id);
|
||||
sender = newStreamSender(s, id);
|
||||
} catch (IOException e) {
|
||||
_log.error("IOException when creating SAM STREAM session socket handler", e);
|
||||
recv.stopStreamReceiving();
|
||||
@@ -318,7 +324,7 @@ public class SAMStreamSession {
|
||||
*
|
||||
* @param id Handler id
|
||||
*/
|
||||
private SAMStreamSessionSocketReader getSocketReader(int id) {
|
||||
protected SAMStreamSessionSocketReader getSocketReader ( int id ) {
|
||||
synchronized (handlersMapLock) {
|
||||
return (SAMStreamSessionSocketReader)handlersMap.get(new Integer(id));
|
||||
}
|
||||
@@ -334,7 +340,7 @@ public class SAMStreamSession {
|
||||
*
|
||||
* @param id Handler id
|
||||
*/
|
||||
private boolean checkSocketHandlerId(int id) {
|
||||
protected boolean checkSocketHandlerId ( int id ) {
|
||||
synchronized (handlersMapLock) {
|
||||
return (!(handlersMap.get(new Integer(id)) == null));
|
||||
}
|
||||
@@ -345,7 +351,7 @@ public class SAMStreamSession {
|
||||
*
|
||||
* @param id Handler id to be removed
|
||||
*/
|
||||
private void removeSocketHandler(int id) {
|
||||
protected void removeSocketHandler ( int id ) {
|
||||
SAMStreamSessionSocketReader reader = null;
|
||||
StreamSender sender = null;
|
||||
|
||||
@@ -446,7 +452,8 @@ public class SAMStreamSession {
|
||||
}
|
||||
|
||||
_log.debug("New connection id: " + id);
|
||||
recv.notifyStreamConnection(id, i2ps.getPeerDestination());
|
||||
|
||||
recv.notifyStreamIncomingConnection ( id, i2ps.getPeerDestination() );
|
||||
} catch (I2PException e) {
|
||||
_log.debug("Caught I2PException", e);
|
||||
break;
|
||||
@@ -469,29 +476,62 @@ public class SAMStreamSession {
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean setReceiveLimit ( int id, long limit, boolean nolimit )
|
||||
{
|
||||
_log.debug ( "Protocol v1 does not support a receive limit for streams" );
|
||||
return false ;
|
||||
}
|
||||
|
||||
/**
|
||||
* SAM STREAM socket handler, running in its own thread. It forwards
|
||||
* SAM STREAM socket reader, running in its own thread. It forwards
|
||||
* forward data to/from an I2P socket.
|
||||
*
|
||||
* @author human
|
||||
*/
|
||||
public class SAMStreamSessionSocketReader implements Runnable {
|
||||
|
||||
private I2PSocket i2pSocket = null;
|
||||
protected I2PSocket i2pSocket = null;
|
||||
|
||||
private Object runningLock = new Object();
|
||||
private boolean stillRunning = true;
|
||||
protected Object runningLock = new Object();
|
||||
|
||||
protected boolean stillRunning = true;
|
||||
|
||||
protected int id;
|
||||
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* Create a new SAM STREAM session socket reader
|
||||
*
|
||||
* @param s Socket to be handled
|
||||
* @param id Unique id assigned to the handler
|
||||
*/
|
||||
public SAMStreamSessionSocketReader(I2PSocket s, int id) throws IOException {
|
||||
_log.debug("Instantiating new SAM STREAM session socket handler");
|
||||
public SAMStreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket reader thread immediately.
|
||||
*/
|
||||
public void stopRunning() {}
|
||||
|
||||
public void run() {}
|
||||
|
||||
}
|
||||
|
||||
protected SAMStreamSessionSocketReader
|
||||
newSAMStreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {
|
||||
return new SAMv1StreamSessionSocketReader ( s, id );
|
||||
}
|
||||
|
||||
public class SAMv1StreamSessionSocketReader extends SAMStreamSessionSocketReader {
|
||||
/**
|
||||
* Create a new SAM STREAM session socket reader
|
||||
*
|
||||
* @param s Socket to be handled
|
||||
* @param id Unique id assigned to the handler
|
||||
*/
|
||||
|
||||
public SAMv1StreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {
|
||||
super(s, id);
|
||||
_log.debug("Instantiating new SAM STREAM session socket reader");
|
||||
|
||||
i2pSocket = s;
|
||||
this.id = id;
|
||||
@@ -507,6 +547,7 @@ public class SAMStreamSession {
|
||||
if (stillRunning) {
|
||||
stillRunning = false;
|
||||
}
|
||||
runningLock.notifyAll() ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +599,40 @@ public class SAMStreamSession {
|
||||
* Lets us push data through the stream without blocking, (even after exceeding
|
||||
* the I2PSocket's buffer)
|
||||
*/
|
||||
private class StreamSender implements Runnable {
|
||||
protected class StreamSender implements Runnable {
|
||||
public StreamSender ( I2PSocket s, int id ) throws IOException {}
|
||||
|
||||
/**
|
||||
* Send bytes through the SAM STREAM session socket sender
|
||||
*
|
||||
* @param data Data to be sent
|
||||
*
|
||||
* @throws IOException if the client didnt provide enough data
|
||||
*/
|
||||
public void sendBytes ( InputStream in, int size ) throws IOException {}
|
||||
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender thread immediately
|
||||
*
|
||||
*/
|
||||
public void stopRunning() {}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender gracefully: stop the
|
||||
* sender thread once all pending data has been sent.
|
||||
*/
|
||||
public void shutDownGracefully() {}
|
||||
|
||||
public void run() {}
|
||||
}
|
||||
|
||||
protected StreamSender newStreamSender ( I2PSocket s, int id ) throws IOException {
|
||||
return new v1StreamSender ( s, id ) ;
|
||||
}
|
||||
|
||||
protected class v1StreamSender extends StreamSender
|
||||
{
|
||||
private List _data;
|
||||
private int _id;
|
||||
private ByteCache _cache;
|
||||
@@ -567,7 +641,8 @@ public class SAMStreamSession {
|
||||
private Object runningLock = new Object();
|
||||
private I2PSocket i2pSocket = null;
|
||||
|
||||
public StreamSender(I2PSocket s, int id) throws IOException {
|
||||
public v1StreamSender ( I2PSocket s, int id ) throws IOException {
|
||||
super ( s, id );
|
||||
_data = new ArrayList(1);
|
||||
_id = id;
|
||||
_cache = ByteCache.getInstance(4, 32*1024);
|
||||
|
@@ -35,6 +35,8 @@ import net.i2p.util.Log;
|
||||
* @author human
|
||||
*/
|
||||
public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver {
|
||||
protected int verMajorId = 1;
|
||||
protected int verMinorId = 0;
|
||||
|
||||
private final static Log _log = new Log(SAMv1Handler.class);
|
||||
|
||||
@@ -42,7 +44,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
|
||||
private SAMRawSession rawSession = null;
|
||||
private SAMDatagramSession datagramSession = null;
|
||||
private SAMStreamSession streamSession = null;
|
||||
protected SAMStreamSession streamSession = null;
|
||||
|
||||
private long _id;
|
||||
private static volatile long __id = 0;
|
||||
@@ -74,11 +76,15 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
_id = ++__id;
|
||||
_log.debug("SAM version 1 handler instantiated");
|
||||
|
||||
if ((this.verMajor != 1) || (this.verMinor != 0)) {
|
||||
if ( ! verifVersion() ) {
|
||||
throw new SAMException("BUG! Wrong protocol version!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean verifVersion() {
|
||||
return ( verMajor == 1 && verMinor == 0 ) ;
|
||||
}
|
||||
|
||||
public void handle() {
|
||||
String msg = null;
|
||||
String domain = null;
|
||||
@@ -248,7 +254,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
props.remove("DIRECTION");
|
||||
|
||||
streamSession = new SAMStreamSession(destKeystream, dir,props,this);
|
||||
streamSession = newSAMStreamSession(destKeystream, dir,props);
|
||||
} else {
|
||||
_log.debug("Unrecognized SESSION STYLE: \"" + style +"\"");
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n");
|
||||
@@ -275,6 +281,13 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props )
|
||||
throws IOException, DataFormatException, SAMException
|
||||
{
|
||||
return new SAMStreamSession(destKeystream, direction, props, this) ;
|
||||
}
|
||||
|
||||
/* Parse and execute a DEST message*/
|
||||
private boolean execDestMessage(String opcode, Properties props) {
|
||||
|
||||
@@ -489,7 +502,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
|
||||
/* Parse and execute a STREAM message */
|
||||
private boolean execStreamMessage(String opcode, Properties props) {
|
||||
protected boolean execStreamMessage(String opcode, Properties props) {
|
||||
if (streamSession == null) {
|
||||
_log.error("STREAM message received, but no STREAM session exists");
|
||||
return false;
|
||||
@@ -508,7 +521,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
}
|
||||
|
||||
private boolean execStreamSend(Properties props) {
|
||||
protected boolean execStreamSend(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM SEND message");
|
||||
return false;
|
||||
@@ -570,7 +583,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
}
|
||||
|
||||
private boolean execStreamConnect(Properties props) {
|
||||
protected boolean execStreamConnect(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CONNECT message");
|
||||
return false;
|
||||
@@ -604,39 +617,38 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
props.remove("DESTINATION");
|
||||
|
||||
try {
|
||||
if (!streamSession.connect(id, dest, props)) {
|
||||
_log.debug("STREAM connection failed");
|
||||
return false;
|
||||
try {
|
||||
if (!streamSession.connect(id, dest, props)) {
|
||||
_log.debug("STREAM connection failed");
|
||||
return false;
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
_log.debug("Invalid destination in STREAM CONNECT message");
|
||||
notifyStreamOutgoingConnection ( id, "INVALID_KEY", null );
|
||||
} catch (SAMInvalidDirectionException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
notifyStreamOutgoingConnection ( id, "INVALID_DIRECTION", null );
|
||||
} catch (ConnectException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
notifyStreamOutgoingConnection ( id, "CONNECTION_REFUSED", null );
|
||||
} catch (NoRouteToHostException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
notifyStreamOutgoingConnection ( id, "CANT_REACH_PEER", null );
|
||||
} catch (InterruptedIOException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
notifyStreamOutgoingConnection ( id, "TIMEOUT", null );
|
||||
} catch (I2PException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
notifyStreamOutgoingConnection ( id, "I2P_ERROR", null );
|
||||
}
|
||||
return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n");
|
||||
} catch (DataFormatException e) {
|
||||
_log.debug("Invalid destination in STREAM CONNECT message");
|
||||
return writeString("STREAM STATUS RESULT=INVALID_KEY ID="
|
||||
+ id + "\n");
|
||||
} catch (SAMInvalidDirectionException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID="
|
||||
+ id + "\n");
|
||||
} catch (ConnectException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID="
|
||||
+ id + "\n");
|
||||
} catch (NoRouteToHostException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID="
|
||||
+ id + "\n");
|
||||
} catch (InterruptedIOException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=TIMEOUT ID="
|
||||
+ id + "\n");
|
||||
} catch (I2PException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=I2P_ERROR ID="
|
||||
+ id + "\n");
|
||||
} catch (IOException e) {
|
||||
return false ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
private boolean execStreamClose(Properties props) {
|
||||
protected boolean execStreamClose(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CLOSE message");
|
||||
return false;
|
||||
@@ -745,7 +757,41 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
|
||||
// SAMStreamReceiver implementation
|
||||
public void notifyStreamConnection(int id, Destination d) throws IOException {
|
||||
|
||||
public void streamSendAnswer( int id, String result, String bufferState ) throws IOException
|
||||
{
|
||||
if ( streamSession == null )
|
||||
{
|
||||
_log.error ( "BUG! Want to answer to stream SEND, but session is null!" );
|
||||
throw new NullPointerException ( "BUG! STREAM session is null!" );
|
||||
}
|
||||
|
||||
if ( !writeString ( "STREAM SEND ID=" + id
|
||||
+ " RESULT=" + result
|
||||
+ " STATE=" + bufferState
|
||||
+ "\n" ) )
|
||||
{
|
||||
throw new IOException ( "Error notifying connection to SAM client" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void notifyStreamSendBufferFree( int id ) throws IOException
|
||||
{
|
||||
if ( streamSession == null )
|
||||
{
|
||||
_log.error ( "BUG! Stream outgoing buffer is free, but session is null!" );
|
||||
throw new NullPointerException ( "BUG! STREAM session is null!" );
|
||||
}
|
||||
|
||||
if ( !writeString ( "STREAM READY_TO_SEND ID=" + id + "\n" ) )
|
||||
{
|
||||
throw new IOException ( "Error notifying connection to SAM client" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void notifyStreamIncomingConnection(int id, Destination d) throws IOException {
|
||||
if (streamSession == null) {
|
||||
_log.error("BUG! Received stream connection, but session is null!");
|
||||
throw new NullPointerException("BUG! STREAM session is null!");
|
||||
@@ -758,6 +804,28 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyStreamOutgoingConnection ( int id, String result, String msg ) throws IOException
|
||||
{
|
||||
if ( streamSession == null )
|
||||
{
|
||||
_log.error ( "BUG! Received stream connection, but session is null!" );
|
||||
throw new NullPointerException ( "BUG! STREAM session is null!" );
|
||||
}
|
||||
|
||||
String msgString = "" ;
|
||||
|
||||
if ( msg != null ) msgString = " MESSAGE=\"" + msg + "\"";
|
||||
|
||||
if ( !writeString ( "STREAM STATUS RESULT="
|
||||
+ result
|
||||
+ " ID=" + id
|
||||
+ msgString
|
||||
+ "\n" ) )
|
||||
{
|
||||
throw new IOException ( "Error notifying connection to SAM client" );
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveStreamBytes(int id, byte data[], int len) throws IOException {
|
||||
if (streamSession == null) {
|
||||
_log.error("Received stream bytes, but session is null!");
|
||||
|
196
apps/sam/java/src/net/i2p/sam/SAMv2Handler.java
Normal file
196
apps/sam/java/src/net/i2p/sam/SAMv2Handler.java
Normal file
@@ -0,0 +1,196 @@
|
||||
package net.i2p.sam;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by human in 2004 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Class able to handle a SAM version 2 client connection.
|
||||
*
|
||||
* @author mkvore
|
||||
*/
|
||||
|
||||
public class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver
|
||||
{
|
||||
|
||||
private final static Log _log = new Log ( SAMv2Handler.class );
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SAM version 2 handler. This constructor expects
|
||||
* that the SAM HELLO message has been still answered (and
|
||||
* stripped) from the socket input stream.
|
||||
*
|
||||
* @param s Socket attached to a SAM client
|
||||
* @param verMajor SAM major version to manage (should be 2)
|
||||
* @param verMinor SAM minor version to manage
|
||||
*/
|
||||
public SAMv2Handler ( Socket s, int verMajor, int verMinor ) throws SAMException, IOException
|
||||
{
|
||||
this ( s, verMajor, verMinor, new Properties() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SAM version 2 handler. This constructor expects
|
||||
* that the SAM HELLO message has been still answered (and
|
||||
* stripped) from the socket input stream.
|
||||
*
|
||||
* @param s Socket attached to a SAM client
|
||||
* @param verMajor SAM major version to manage (should be 2)
|
||||
* @param verMinor SAM minor version to manage
|
||||
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
|
||||
*/
|
||||
|
||||
public SAMv2Handler ( Socket s, int verMajor, int verMinor, Properties i2cpProps ) throws SAMException, IOException
|
||||
{
|
||||
super ( s, verMajor, verMinor, i2cpProps );
|
||||
}
|
||||
|
||||
public boolean verifVersion()
|
||||
{
|
||||
return (verMajor == 2 && verMinor == 0) ;
|
||||
}
|
||||
|
||||
SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props )
|
||||
throws IOException, DataFormatException, SAMException
|
||||
{
|
||||
return new SAMv2StreamSession(destKeystream, direction, props, this) ;
|
||||
}
|
||||
|
||||
|
||||
/* Parse and execute a STREAM message */
|
||||
protected boolean execStreamMessage ( String opcode, Properties props )
|
||||
{
|
||||
if ( streamSession == null )
|
||||
{
|
||||
_log.error ( "STREAM message received, but no STREAM session exists" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( opcode.equals ( "SEND" ) )
|
||||
{
|
||||
return execStreamSend ( props );
|
||||
}
|
||||
else if ( opcode.equals ( "CONNECT" ) )
|
||||
{
|
||||
return execStreamConnect ( props );
|
||||
}
|
||||
else if ( opcode.equals ( "CLOSE" ) )
|
||||
{
|
||||
return execStreamClose ( props );
|
||||
}
|
||||
else if ( opcode.equals ( "RECEIVE") )
|
||||
{
|
||||
return execStreamReceive( props );
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.debug ( "Unrecognized RAW message opcode: \""
|
||||
+ opcode + "\"" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private boolean execStreamReceive ( Properties props )
|
||||
{
|
||||
if ( props == null )
|
||||
{
|
||||
_log.debug ( "No parameters specified in STREAM RECEIVE message" );
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
|
||||
{
|
||||
String strid = props.getProperty ( "ID" );
|
||||
|
||||
if ( strid == null )
|
||||
{
|
||||
_log.debug ( "ID not specified in STREAM RECEIVE message" );
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
id = Integer.parseInt ( strid );
|
||||
}
|
||||
catch ( NumberFormatException e )
|
||||
{
|
||||
_log.debug ( "Invalid STREAM RECEIVE ID specified: " + strid );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean nolimit = false;
|
||||
|
||||
long limit = 0;
|
||||
{
|
||||
String strsize = props.getProperty ( "LIMIT" );
|
||||
|
||||
if ( strsize == null )
|
||||
{
|
||||
_log.debug ( "Limit not specified in STREAM RECEIVE message" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( strsize.equals( "NONE" ) )
|
||||
{
|
||||
nolimit = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
limit = Long.parseLong ( strsize );
|
||||
}
|
||||
catch ( NumberFormatException e )
|
||||
{
|
||||
_log.debug ( "Invalid STREAM RECEIVE size specified: " + strsize );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( limit < 0 )
|
||||
{
|
||||
_log.debug ( "Specified limit (" + limit
|
||||
+ ") is out of protocol limits" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streamSession.setReceiveLimit ( id, limit, nolimit ) ;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
574
apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java
Normal file
574
apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java
Normal file
@@ -0,0 +1,574 @@
|
||||
package net.i2p.sam;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by human in 2004 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* SAMv2 STREAM session class.
|
||||
*
|
||||
* @author mkvore
|
||||
*/
|
||||
|
||||
public class SAMv2StreamSession extends SAMStreamSession
|
||||
{
|
||||
|
||||
private final static Log _log = new Log ( SAMv2StreamSession.class );
|
||||
|
||||
/**
|
||||
* Create a new SAM STREAM session.
|
||||
*
|
||||
* @param dest Base64-encoded destination (private key)
|
||||
* @param dir Session direction ("RECEIVE", "CREATE" or "BOTH")
|
||||
* @param props Properties to setup the I2P session
|
||||
* @param recv Object that will receive incoming data
|
||||
*/
|
||||
public SAMv2StreamSession ( String dest, String dir, Properties props,
|
||||
SAMStreamReceiver recv ) throws IOException, DataFormatException, SAMException
|
||||
{
|
||||
super ( dest, dir, props, recv );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SAM STREAM session.
|
||||
*
|
||||
* @param destStream Input stream containing the destination keys
|
||||
* @param dir Session direction ("RECEIVE", "CREATE" or "BOTH")
|
||||
* @param props Properties to setup the I2P session
|
||||
* @param recv Object that will receive incoming data
|
||||
*/
|
||||
public SAMv2StreamSession ( InputStream destStream, String dir,
|
||||
Properties props, SAMStreamReceiver recv ) throws IOException, DataFormatException, SAMException
|
||||
{
|
||||
super ( destStream, dir, props, recv );
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect the SAM STREAM session to the specified Destination
|
||||
*
|
||||
* @param id Unique id for the connection
|
||||
* @param dest Base64-encoded Destination to connect to
|
||||
* @param props Options to be used for connection
|
||||
*
|
||||
* @throws DataFormatException if the destination is not valid
|
||||
* @throws SAMInvalidDirectionException if trying to connect through a
|
||||
* receive-only session
|
||||
* @return true if the communication with the SAM client is ok
|
||||
*/
|
||||
|
||||
public boolean connect ( int id, String dest, Properties props )
|
||||
throws DataFormatException, SAMInvalidDirectionException
|
||||
{
|
||||
if ( !canCreate )
|
||||
{
|
||||
_log.debug ( "Trying to create an outgoing connection using a receive-only session" );
|
||||
throw new SAMInvalidDirectionException ( "Trying to create connections through a receive-only session" );
|
||||
}
|
||||
|
||||
if ( checkSocketHandlerId ( id ) )
|
||||
{
|
||||
_log.debug ( "The specified id (" + id + ") is already in use" );
|
||||
return false ;
|
||||
}
|
||||
|
||||
Destination d = new Destination();
|
||||
|
||||
d.fromBase64 ( dest );
|
||||
|
||||
I2PSocketOptions opts = socketMgr.buildOptions ( props );
|
||||
|
||||
if ( props.getProperty ( I2PSocketOptions.PROP_CONNECT_TIMEOUT ) == null )
|
||||
opts.setConnectTimeout ( 60 * 1000 );
|
||||
|
||||
_log.debug ( "Connecting new I2PSocket..." );
|
||||
|
||||
|
||||
// non-blocking connection (SAMv2)
|
||||
|
||||
StreamConnector connector ;
|
||||
|
||||
connector = new StreamConnector ( id, d, opts );
|
||||
|
||||
I2PThread connectThread = new I2PThread ( connector, "StreamConnector" + id ) ;
|
||||
|
||||
connectThread.start() ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SAM STREAM socket connecter, running in its own thread.
|
||||
*
|
||||
* @author mkvore
|
||||
*/
|
||||
|
||||
public class StreamConnector implements Runnable
|
||||
{
|
||||
|
||||
private Object runningLock = new Object();
|
||||
private boolean stillRunning = true;
|
||||
|
||||
private int id;
|
||||
private Destination dest ;
|
||||
private I2PSocketOptions opts ;
|
||||
|
||||
/**
|
||||
* Create a new SAM STREAM session socket reader
|
||||
*
|
||||
* @param id Unique id assigned to the handler
|
||||
* @param dest Destination to reach
|
||||
* @param opts Socket options (I2PSocketOptions)
|
||||
*/
|
||||
|
||||
|
||||
public StreamConnector ( int id, Destination dest, I2PSocketOptions opts )// throws IOException
|
||||
{
|
||||
_log.debug ( "Instantiating new SAM STREAM connector" );
|
||||
|
||||
this.id = id ;
|
||||
this.opts = opts ;
|
||||
this.dest = dest ;
|
||||
}
|
||||
|
||||
|
||||
public void run()
|
||||
{
|
||||
_log.debug ( "run() called for socket connector " + id );
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
I2PSocket i2ps = socketMgr.connect ( dest, opts );
|
||||
|
||||
createSocketHandler ( i2ps, id );
|
||||
|
||||
recv.notifyStreamOutgoingConnection ( id, "OK", null );
|
||||
}
|
||||
|
||||
catch ( DataFormatException e )
|
||||
{
|
||||
_log.debug ( "Invalid destination in STREAM CONNECT message" );
|
||||
recv.notifyStreamOutgoingConnection ( id, "INVALID_KEY", e.getMessage() );
|
||||
}
|
||||
catch ( ConnectException e )
|
||||
{
|
||||
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
|
||||
recv.notifyStreamOutgoingConnection ( id, "CONNECTION_REFUSED", e.getMessage() );
|
||||
}
|
||||
catch ( NoRouteToHostException e )
|
||||
{
|
||||
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
|
||||
recv.notifyStreamOutgoingConnection ( id, "CANT_REACH_PEER", e.getMessage() );
|
||||
}
|
||||
catch ( InterruptedIOException e )
|
||||
{
|
||||
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
|
||||
recv.notifyStreamOutgoingConnection ( id, "TIMEOUT", e.getMessage() );
|
||||
}
|
||||
catch ( I2PException e )
|
||||
{
|
||||
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
|
||||
recv.notifyStreamOutgoingConnection ( id, "I2P_ERROR", e.getMessage() );
|
||||
}
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
_log.debug ( "Error sending disconnection notice for handler "
|
||||
+ id, e );
|
||||
}
|
||||
|
||||
_log.debug ( "Shutting down SAM STREAM session connector " + id );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Lets us push data through the stream without blocking, (even after exceeding
|
||||
* the I2PSocket's buffer)
|
||||
*/
|
||||
|
||||
protected StreamSender newStreamSender ( I2PSocket s, int id ) throws IOException
|
||||
{
|
||||
return new v2StreamSender ( s, id ) ;
|
||||
}
|
||||
|
||||
protected SAMStreamSessionSocketReader
|
||||
newSAMStreamSessionSocketReader(I2PSocket s, int id ) throws IOException
|
||||
{
|
||||
return new SAMv2StreamSessionSocketReader(s,id);
|
||||
}
|
||||
|
||||
protected class v2StreamSender extends StreamSender
|
||||
|
||||
{
|
||||
private List _data;
|
||||
private int _dataSize;
|
||||
private int _id;
|
||||
private ByteCache _cache;
|
||||
private OutputStream _out = null;
|
||||
private boolean _stillRunning, _shuttingDownGracefully;
|
||||
private Object runningLock = new Object();
|
||||
private I2PSocket i2pSocket = null;
|
||||
|
||||
public v2StreamSender ( I2PSocket s, int id ) throws IOException
|
||||
{
|
||||
super ( s, id );
|
||||
_data = new ArrayList ( 1 );
|
||||
_dataSize = 0;
|
||||
_id = id;
|
||||
_cache = ByteCache.getInstance ( 10, 32 * 1024 );
|
||||
_out = s.getOutputStream();
|
||||
_stillRunning = true;
|
||||
_shuttingDownGracefully = false;
|
||||
i2pSocket = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send bytes through the SAM STREAM session socket sender
|
||||
*
|
||||
* @param data Data to be sent
|
||||
*
|
||||
* @throws IOException if the client didnt provide enough data
|
||||
*/
|
||||
public void sendBytes ( InputStream in, int size ) throws IOException
|
||||
{
|
||||
if ( _log.shouldLog ( Log.DEBUG ) )
|
||||
_log.debug ( "Handler " + _id + ": sending " + size + " bytes" );
|
||||
|
||||
ByteArray ba = _cache.acquire();
|
||||
|
||||
int read = DataHelper.read ( in, ba.getData(), 0, size );
|
||||
|
||||
if ( read != size )
|
||||
throw new IOException ( "Insufficient data from the SAM client (" + read + "/" + size + ")" );
|
||||
|
||||
ba.setValid ( read );
|
||||
|
||||
synchronized ( _data )
|
||||
{
|
||||
if ( _dataSize >= SOCKET_HANDLER_BUF_SIZE )
|
||||
{
|
||||
_cache.release ( ba, false );
|
||||
recv.streamSendAnswer ( _id, "FAILED", "BUFFER_FULL" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataSize += size ;
|
||||
_data.add ( ba );
|
||||
_data.notifyAll();
|
||||
|
||||
if ( _dataSize >= SOCKET_HANDLER_BUF_SIZE )
|
||||
{
|
||||
recv.streamSendAnswer ( _id, "OK", "BUFFER_FULL" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv.streamSendAnswer ( _id, "OK", "READY" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender thread immediately
|
||||
*
|
||||
*/
|
||||
public void stopRunning()
|
||||
{
|
||||
_log.debug ( "stopRunning() invoked on socket sender " + _id );
|
||||
|
||||
synchronized ( runningLock )
|
||||
{
|
||||
if ( _stillRunning )
|
||||
{
|
||||
_stillRunning = false;
|
||||
|
||||
try
|
||||
{
|
||||
i2pSocket.close();
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
_log.debug ( "Caught IOException", e );
|
||||
}
|
||||
|
||||
synchronized ( _data )
|
||||
{
|
||||
_data.clear();
|
||||
_data.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a SAM STREAM session socket sender gracefully: stop the
|
||||
* sender thread once all pending data has been sent.
|
||||
*/
|
||||
public void shutDownGracefully()
|
||||
{
|
||||
_log.debug ( "shutDownGracefully() invoked on socket sender " + _id );
|
||||
_shuttingDownGracefully = true;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
_log.debug ( "run() called for socket sender " + _id );
|
||||
ByteArray data = null;
|
||||
|
||||
while ( _stillRunning )
|
||||
{
|
||||
data = null;
|
||||
|
||||
try
|
||||
{
|
||||
synchronized ( _data )
|
||||
{
|
||||
if ( _data.size() > 0 )
|
||||
{
|
||||
int formerSize = _dataSize ;
|
||||
data = ( ByteArray ) _data.remove ( 0 );
|
||||
_dataSize -= data.getValid();
|
||||
|
||||
if ( ( formerSize >= SOCKET_HANDLER_BUF_SIZE ) && ( _dataSize < SOCKET_HANDLER_BUF_SIZE ) )
|
||||
recv.notifyStreamSendBufferFree ( _id );
|
||||
}
|
||||
else if ( _shuttingDownGracefully )
|
||||
{
|
||||
/* No data left and shutting down gracefully?
|
||||
If so, stop the sender. */
|
||||
stopRunning();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for data. */
|
||||
_data.wait ( 5000 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( data != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
_out.write ( data.getData(), 0, data.getValid() );
|
||||
|
||||
if ( forceFlush )
|
||||
{
|
||||
// i dont like doing this, but it clears the buffer issues
|
||||
_out.flush();
|
||||
}
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
// ok, the stream failed, but the SAM client didn't
|
||||
|
||||
if ( _log.shouldLog ( Log.WARN ) )
|
||||
_log.warn ( "Stream failed", ioe );
|
||||
|
||||
removeSocketHandler ( _id );
|
||||
|
||||
stopRunning();
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
_cache.release ( data, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( InterruptedException ie ) {}
|
||||
catch ( IOException e ) {}}
|
||||
|
||||
synchronized ( _data )
|
||||
{
|
||||
_data.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send bytes through a SAM STREAM session.
|
||||
*
|
||||
* @param data Bytes to be sent
|
||||
*
|
||||
* @return True if the data was queued for sending, false otherwise
|
||||
*/
|
||||
public boolean setReceiveLimit ( int id, long limit, boolean nolimit )
|
||||
{
|
||||
SAMStreamSessionSocketReader reader = getSocketReader ( id );
|
||||
|
||||
if ( reader == null )
|
||||
{
|
||||
if ( _log.shouldLog ( Log.WARN ) )
|
||||
_log.warn ( "Trying to set a limit to a nonexistent reader " + id );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SAMv2StreamSessionSocketReader) reader).setLimit ( limit, nolimit );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SAM STREAM socket reader, running in its own thread. It forwards
|
||||
* forward data to/from an I2P socket.
|
||||
*
|
||||
* @author human
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public class SAMv2StreamSessionSocketReader extends SAMv1StreamSessionSocketReader
|
||||
{
|
||||
|
||||
protected boolean nolimit ;
|
||||
protected long limit ;
|
||||
protected long totalReceived ;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SAM STREAM session socket reader
|
||||
*
|
||||
* @param s Socket to be handled
|
||||
* @param id Unique id assigned to the handler
|
||||
*/
|
||||
public SAMv2StreamSessionSocketReader ( I2PSocket s, int id ) throws IOException
|
||||
{
|
||||
super ( s, id );
|
||||
nolimit = false ;
|
||||
limit = 0 ;
|
||||
totalReceived = 0 ;
|
||||
}
|
||||
|
||||
public void setLimit ( long limit, boolean nolimit )
|
||||
{
|
||||
synchronized (runningLock)
|
||||
{
|
||||
this.limit = limit ;
|
||||
this.nolimit = nolimit ;
|
||||
runningLock.notify() ;
|
||||
}
|
||||
_log.debug ( "new limit set for socket reader " + id + " : " + (nolimit ? "NOLIMIT" : limit + " bytes" ) );
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
_log.debug ( "run() called for socket reader " + id );
|
||||
|
||||
int read = -1;
|
||||
byte[] data = new byte[SOCKET_HANDLER_BUF_SIZE];
|
||||
|
||||
try
|
||||
{
|
||||
InputStream in = i2pSocket.getInputStream();
|
||||
|
||||
while ( stillRunning )
|
||||
{
|
||||
synchronized (runningLock)
|
||||
{
|
||||
while ( stillRunning && ( !nolimit && totalReceived >= limit) )
|
||||
{
|
||||
try{
|
||||
runningLock.wait() ;
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{}
|
||||
}
|
||||
if ( !stillRunning )
|
||||
break ;
|
||||
}
|
||||
|
||||
read = in.read ( data );
|
||||
|
||||
if ( read == -1 )
|
||||
{
|
||||
_log.debug ( "Handler " + id + ": connection closed" );
|
||||
break;
|
||||
}
|
||||
|
||||
totalReceived += read ;
|
||||
|
||||
recv.receiveStreamBytes ( id, data, read );
|
||||
}
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
_log.debug ( "Caught IOException", e );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
i2pSocket.close();
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
_log.debug ( "Caught IOException", e );
|
||||
}
|
||||
|
||||
if ( stillRunning )
|
||||
{
|
||||
removeSocketHandler ( id );
|
||||
// FIXME: we need error reporting here!
|
||||
|
||||
try
|
||||
{
|
||||
recv.notifyStreamDisconnection ( id, "OK", null );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
_log.debug ( "Error sending disconnection notice for handler "
|
||||
+ id, e );
|
||||
}
|
||||
}
|
||||
|
||||
_log.debug ( "Shutting down SAM STREAM session socket handler " + id );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -302,24 +302,35 @@ public class ConnectionPacketHandler {
|
||||
_context.statManager().addRateData("stream.trend", trend, newWindowSize);
|
||||
|
||||
if ( (!congested) && (acked > 0) && (numResends <= 0) ) {
|
||||
if (trend < 0) {
|
||||
if (newWindowSize < con.getLastCongestionSeenAt() / 2) {
|
||||
// Don't make this <= LastCongestion/2 or we'll jump right back to where we were
|
||||
// slow start - exponential growth
|
||||
// grow acked/N times (where N = the slow start factor)
|
||||
// always grow at least 1
|
||||
int factor = con.getOptions().getSlowStartGrowthRateFactor();
|
||||
if (factor <= 1)
|
||||
newWindowSize += acked;
|
||||
else if (acked < factor)
|
||||
newWindowSize++;
|
||||
else
|
||||
newWindowSize += acked / factor;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("slow start acks = " + acked + " for " + con);
|
||||
} else if (trend < 0) {
|
||||
// rtt is shrinking, so lets increment the cwin
|
||||
newWindowSize++;
|
||||
} else if (newWindowSize > con.getLastCongestionSeenAt() / 2) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("trend < 0 for " + con);
|
||||
} else {
|
||||
// congestion avoidance
|
||||
|
||||
// we can't use newWindowSize += 1/newWindowSize, since we're
|
||||
// linear growth - increase window 1/N per RTT
|
||||
// we can't use newWindowSize += acked/(oldWindow*N) (where N = the cong. avoid. factor), since we're
|
||||
// integers, so lets use a random distribution instead
|
||||
int shouldIncrement = _context.random().nextInt(con.getOptions().getCongestionAvoidanceGrowthRateFactor()*newWindowSize);
|
||||
if (shouldIncrement <= 0)
|
||||
newWindowSize += 1;
|
||||
} else {
|
||||
// slow start, but modified to take into account the fact
|
||||
// that windows in the streaming lib are messages, not bytes,
|
||||
// so we only grow 1 every N times (where N = the slow start factor)
|
||||
int shouldIncrement = _context.random().nextInt(con.getOptions().getSlowStartGrowthRateFactor());
|
||||
if (shouldIncrement <= 0)
|
||||
if (shouldIncrement < acked)
|
||||
newWindowSize += 1;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("cong. avoid acks = " + acked + " for " + con);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -129,7 +129,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
public long getAcceptTimeout() { return _acceptTimeout; }
|
||||
|
||||
public void setDefaultOptions(I2PSocketOptions options) {
|
||||
_defaultOptions = new ConnectionOptions(options);
|
||||
_defaultOptions = new ConnectionOptions((ConnectionOptions) options);
|
||||
}
|
||||
|
||||
public I2PSocketOptions getDefaultOptions() {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
* $Revision: 1.2 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
@@ -76,6 +76,8 @@ public class AddressbookBean
|
||||
deletionMarks = new LinkedList();
|
||||
}
|
||||
private long configLastLoaded = 0;
|
||||
private static final String PRIVATE_BOOK = "private_addressbook";
|
||||
private static final String DEFAULT_PRIVATE_BOOK = "../privatehosts.txt";
|
||||
private void loadConfig()
|
||||
{
|
||||
long currentTime = System.currentTimeMillis();
|
||||
@@ -86,6 +88,9 @@ public class AddressbookBean
|
||||
try {
|
||||
properties.clear();
|
||||
properties.load( new FileInputStream( ConfigBean.configFileName ) );
|
||||
// added in 0.5, for compatibility with 0.4 config.txt
|
||||
if( properties.getProperty(PRIVATE_BOOK) == null)
|
||||
properties.setProperty(PRIVATE_BOOK, DEFAULT_PRIVATE_BOOK);
|
||||
configLastLoaded = currentTime;
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -112,8 +117,9 @@ public class AddressbookBean
|
||||
public String getBook()
|
||||
{
|
||||
if( book == null || ( book.compareToIgnoreCase( "master" ) != 0 &&
|
||||
book.compareToIgnoreCase( "router" ) != 0 ) &&
|
||||
book.compareToIgnoreCase( "published" ) != 0 )
|
||||
book.compareToIgnoreCase( "router" ) != 0 &&
|
||||
book.compareToIgnoreCase( "private" ) != 0 &&
|
||||
book.compareToIgnoreCase( "published" ) != 0 ))
|
||||
book = "master";
|
||||
|
||||
return book;
|
||||
@@ -163,7 +169,11 @@ public class AddressbookBean
|
||||
list.addLast( new AddressBean( name, destination ) );
|
||||
}
|
||||
// Format a message about filtered addressbook size, and the number of displayed entries
|
||||
message = "Filtered list contains " + list.size() + " entries";
|
||||
if( filter != null && filter.length() > 0 )
|
||||
message = "Filtered l";
|
||||
else
|
||||
message = "L";
|
||||
message += "ist contains " + list.size() + " entries";
|
||||
if (list.size() > 300) message += ", displaying the first 300."; else message += ".";
|
||||
|
||||
Object array[] = list.toArray();
|
||||
@@ -251,6 +261,10 @@ public class AddressbookBean
|
||||
{
|
||||
return getBook().compareToIgnoreCase( "published" ) == 0;
|
||||
}
|
||||
public boolean isPrivate()
|
||||
{
|
||||
return getBook().compareToIgnoreCase( "private" ) == 0;
|
||||
}
|
||||
public void setFilter(String filter) {
|
||||
if( filter != null && ( filter.length() == 0 || filter.compareToIgnoreCase( "none" ) == 0 ) ) {
|
||||
filter = null;
|
||||
|
@@ -19,14 +19,14 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
public class VersionBean {
|
||||
|
||||
private static String version = "0.4";
|
||||
private static String version = "0.5";
|
||||
private static String url = "http://susi.i2p/?i2paddresshelper=T2DU1KAz3meB0B53U8Y06-I7vHR7XmC0qXAJfLW6b-1L1FVKoySRZz4xazHAwyv2xtRpvKrv6ukLm1tThEW0zQWtZPtX8G6KkzMibD8t7IS~4yw-9VkBtUydyYfsX08AK3v~-egSW8HCXTdyIJVtrETJb337VDUHW-7D4L1JLbwSH4if2ooks6yFTrljK5aVMi-16dZOVvmoyJc3jBqSdK6kraO4gW5-vHTmbLwL498p9nug1KOg1DqgN2GeU5X1QlVrlpFb~IIfdP~O8NT7u-LAjW3jSJsMbLDHMSYTIhC7xmJIiBoi-qk8p6TLynAmvJ7HRvbx4N1EB-uJHyD16wsZkkHyEOfmXbj0ZqLyKEGb3thPwCz-M9v~c2Qt3WbwjXJAtHpjlHkdJ4Fg91cX2oak~JoapnPf6Syw8hko5syf6VVoCYLnrrYyM8oGl8mLclHkj~VCidQNqMSM74IhrHfK6HmRikqtZBexb5M6wfMTTqBvaHURdD21GOpFKYBUAAAA";
|
||||
|
||||
public String getVersion() {
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.2 $
|
||||
* $Revision: 1.3 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
@@ -48,9 +48,11 @@
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="addressbook.jsp?book=published">published</a> |
|
||||
<a href="addressbook.jsp?book=private">private</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
<a href="config.jsp">configuration</a> *
|
||||
<a href="index.jsp">overview</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -92,7 +94,8 @@
|
||||
<a href="addressbook.jsp?filter=0-9">0-9</a>
|
||||
<a href="addressbook.jsp?filter=none">all</a></p>
|
||||
<c:if test="${book.hasFilter}">
|
||||
<p>Current filter: ${book.filter}</p>
|
||||
<p>Current filter: ${book.filter}
|
||||
(<a href="addressbook.jsp?filter=none">clear filter</a>)</p>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +120,7 @@
|
||||
<table class="book" cellspacing="0" cellpadding="5">
|
||||
<tr class="head">
|
||||
|
||||
<c:if test="${book.master || book.router || book.published}">
|
||||
<c:if test="${book.master || book.router || book.published || book.private}">
|
||||
<th> </th>
|
||||
</c:if>
|
||||
|
||||
@@ -127,7 +130,7 @@
|
||||
<!-- limit iterator to 300, or "Form too large" may result on submit -->
|
||||
<c:forEach items="${book.entries}" var="addr" begin="0" end="299">
|
||||
<tr class="list${book.trClass}">
|
||||
<c:if test="${book.master || book.router || book.published}">
|
||||
<c:if test="${book.master || book.router || book.published || book.private}">
|
||||
<td class="checkbox"><input type="checkbox" name="checked" value="${addr.name}" alt="Mark for deletion"></td>
|
||||
</c:if>
|
||||
<td class="names"><a href="http://${addr.name}/">${addr.name}</a> -
|
||||
@@ -139,7 +142,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<c:if test="${book.master || book.router || book.published}">
|
||||
<c:if test="${book.master || book.router || book.published || book.private}">
|
||||
<div id="buttons">
|
||||
<p class="buttons"><input type="image" name="action" value="delete" src="images/delete.png" alt="Delete checked" />
|
||||
</p>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.14 $
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html" %>
|
||||
@@ -43,9 +43,11 @@
|
||||
addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="addressbook.jsp?book=published">published</a> |
|
||||
<a href="addressbook.jsp?book=private">private</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
configuration *
|
||||
<a href="index.jsp">overview</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="headline">
|
||||
@@ -65,22 +67,22 @@ addressbooks
|
||||
<div id="help">
|
||||
<h3>Hints</h3>
|
||||
<ol>
|
||||
<li>All file or directory paths here are relative to the addressbooks working directory, which normally
|
||||
<li>All file or directory paths here are relative to the addressbook's working directory, which normally
|
||||
is located at $I2P/addressbook/.</li>
|
||||
<li>If you want to manually add lines to an addressbook, add them to the master addressbook. The router
|
||||
<li>If you want to manually add lines to an addressbook, add them to the private or master addressbooks. The router
|
||||
addressbook and the published addressbook are overwritten by the addressbook application.</li>
|
||||
<li><b>Important:</b>When you publish your addressbook, <b>ALL</b> destinations appear there, even those
|
||||
from your master addressbook. Unfortunately the master addressbook points to your userhosts.txt, which was
|
||||
used for private destinations before. So if you want to keep the destinations in your userhosts.txt secret,
|
||||
please change the master addressbook to a different file before turning on addressbook publishing.</li>
|
||||
<li><b>Important:</b>When you publish your addressbook, <b>ALL</b> destinations from the master and router addressbooks appear there.
|
||||
Use the private addressbook for private destinations, these are not published.
|
||||
</li>
|
||||
</ol>
|
||||
<h3>Options</h3>
|
||||
<ul>
|
||||
<li><b>subscriptions</b> - file containing the list of subscriptions URLs (no need to change)</li>
|
||||
<li><b>update_delay</b> - update interval in hours (no need to change)</li>
|
||||
<li><b>published_addressbook</b> - your public hosts.txt file (choose a path within your webserver document root)</li>
|
||||
<li><b>router_addressbook</b> - your hosts.txt (no need to change)</li>
|
||||
<li><b>master_addressbook</b> - your personal addressbook, it gets never overwritten by the addressbook</li>
|
||||
<li><b>router_addressbook</b> - your hosts.txt (don't change)</li>
|
||||
<li><b>master_addressbook</b> - your personal addressbook, it never gets overwritten by the addressbook (don't change)</li>
|
||||
<li><b>private_addressbook</b> - your private addressbook, it is never published (defaults to ../privatehosts.txt, don't change)</li>
|
||||
<li><b>proxy_port</b> - http port for your eepProxy (no need to change)</li>
|
||||
<li><b>proxy_host</b> - hostname for your eepProxy (no need to change)</li>
|
||||
<li><b>should_publish</b> - true/false whether to write the published addressbook</li>
|
||||
@@ -93,4 +95,4 @@ please change the master addressbook to a different file before turning on addre
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005 </p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
* $Revision: 1.2 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
@@ -42,9 +42,11 @@
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="addressbook.jsp?book=published">published</a> |
|
||||
<a href="addressbook.jsp?book=private">private</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
<a href="config.jsp">configuration</a> *
|
||||
overview
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -52,23 +54,25 @@
|
||||
<h3>Huh? what addressbook?</h3>
|
||||
<p>
|
||||
The addressbook application is part of your i2p installation. It regularly updates your hosts.txt file
|
||||
from distributed sources. It keeps your hosts.txt up to date, so it automatically contains all new
|
||||
eepsites announced on <a href="http://orion.i2p">orion</a>
|
||||
or in the <a href="http://forum.i2p/viewforum.php?f=16">forum</a>.
|
||||
from distributed sources. It keeps your hosts.txt up to date, so it can automatically add
|
||||
eepsites announced on other sites if you subscribe to those sites' addressbooks.
|
||||
</p>
|
||||
<p>
|
||||
(To speak the truth: In its default configuration the addressbook does not poll
|
||||
orion, but dev.i2p only. Subscribing to <a href="http://orion.i2p">orion</a> is an easy task,
|
||||
just add <a href="http://orion.i2p/hosts.txt">http://orion.i2p/hosts.txt</a> to your <a href="subscriptions.jsp">subscriptions</a> file.)
|
||||
additional sites, but www.i2p2.i2p only. Subscribing to additional sites is an easy task,
|
||||
just add them to your <a href="subscriptions.jsp">subscriptions</a> file.)
|
||||
</p>
|
||||
<p>If you have questions about naming in i2p, there is an excellent <a href="http://forum.i2p.net/viewtopic.php?t=134">introduction</a>
|
||||
from duck in the forum.</p>
|
||||
<p>If you have questions about naming in i2p, there is an excellent <a href="http://forum.i2p/viewtopic.php?t=134">introduction</a>
|
||||
from duck in the forum and <a href="http://www.i2p2.i2p/naming.html">additional information on www.i2p2.i2p</a>.</p>
|
||||
<h3>How does the addressbook work?</h3>
|
||||
<p>The addressbook application regularly (normally once per hour) polls your subscriptions and merges their content
|
||||
into your so called router addressbook (normally your plain hosts.txt). Then it merges your so called master addressbook (normally
|
||||
your userhosts.txt) into the router addressbook as well. If configured the router addressbook is now written to the so published addressbook,
|
||||
which is a publicly available copy of your hosts.txt somewhere in your eepsites document root. (Yes, this means that, with activated publication,
|
||||
your once private keys from userhosts.txt now are publicly available for everybody.)
|
||||
into your so-called router addressbook (normally your plain hosts.txt). Then it merges your so-called master addressbook (normally
|
||||
your userhosts.txt) into the router addressbook as well. If configured, the router addressbook is now written to the published addressbook,
|
||||
which is a publicly available copy of your hosts.txt somewhere in your eepsite's document root.
|
||||
</p><p>
|
||||
The router also uses a private addressbook (privatehosts.txt, not shown in the picture), which is not merged or published.
|
||||
Hosts in the private addressbook can be accessed by you but their addresses are never distributed to others.
|
||||
The private addressbook can also be used for aliases of hosts in your other addressbooks.
|
||||
</p>
|
||||
<p><img src="images/how.png" border="0" alt="addressbook working scheme"/></p>
|
||||
</div>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.7 $
|
||||
* $Revision: 1.2 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
@@ -42,9 +42,11 @@
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
<a href="addressbook.jsp?book=published">published</a> |
|
||||
<a href="addressbook.jsp?book=private">private</a> *
|
||||
subscriptions *
|
||||
<a href="config.jsp">configuration</a> *
|
||||
<a href="index.jsp">overview</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="headline">
|
||||
@@ -66,9 +68,8 @@
|
||||
<p class="help">
|
||||
The subscription file contains a list of (i2p) URLs. The addressbook application
|
||||
regularly (once per hour) checks this list for new eepsites. Those URLs simply contain the published hosts.txt
|
||||
file of other people. Default subscription is the hosts.txt from dev.i2p. The most
|
||||
popular collaboration site for eepsite is orion.i2p. So its a good idea to add http://orion.i2p/hosts.txt
|
||||
as a 2nd subscription.
|
||||
file of other people. The default subscription is the hosts.txt from www.i2p2.i2p, which is updated infrequently.
|
||||
So it is a good idea to add additional subscriptions to sites that have the latest addresses.
|
||||
</p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
|
@@ -1578,7 +1578,7 @@ public class WebMail extends HttpServlet
|
||||
"<tr><td>Host</td><td><input type=\"text\" size=\"32\" name=\"" + HOST +"\" value=\"" + host + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
|
||||
"<tr><td>POP3-Port</td><td><input type=\"text\" size=\"32\" name=\"" + POP3 +"\" value=\"" + pop3 + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
|
||||
"<tr><td>SMTP-Port</td><td><input type=\"text\" size=\"32\" name=\"" + SMTP +"\" value=\"" + smtp + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
|
||||
"<tr><td align=\"center\" colspan=\"2\">" + button( LOGIN, "Login" ) + " <input type=\"reset\" value=\"Reset\"></td></tr>\n" +
|
||||
"<tr><td align=\"center\" colspan=\"2\"><a href=\"http://hq.postman.i2p/?page_id=16\">Create Account</a> " + button( LOGIN, "Login" ) + " <input type=\"reset\" value=\"Reset\"></td></tr>\n" +
|
||||
"</table>");
|
||||
}
|
||||
/**
|
||||
|
@@ -3,7 +3,8 @@
|
||||
|
||||
<target name="all" >
|
||||
<echo message="Useful targets: " />
|
||||
<echo message=" dist: distclean then package everything up (installer, clean tarball, update tarball)" />
|
||||
<echo message=" pkg: distclean then package everything up (installer, clean tarball, update tarball)" />
|
||||
<echo message=" dist: pkg and javadoc" />
|
||||
<echo message=" installer: build the GUI installer" />
|
||||
<echo message=" tarball: tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" />
|
||||
<echo message=" updater: tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" />
|
||||
@@ -42,7 +43,7 @@
|
||||
<copy file="router/java/build/router.jar" todir="build/" />
|
||||
</target>
|
||||
<target name="buildWEB">
|
||||
<ant dir="apps/jetty" target="fetchJettylib" />
|
||||
<ant dir="apps/jetty" target="ensureJettylib" />
|
||||
<ant dir="apps/routerconsole/java" target="build" />
|
||||
<copy file="apps/routerconsole/java/build/routerconsole.jar" todir="build/" />
|
||||
<copy file="apps/routerconsole/java/build/routerconsole.war" todir="build/" />
|
||||
@@ -138,6 +139,9 @@
|
||||
<pathelement location="apps/i2ptunnel/java/src" />
|
||||
<pathelement location="apps/systray/java/src" />
|
||||
<pathelement location="apps/routerconsole/java/src" />
|
||||
<pathelement location="apps/addressbook/java/src" />
|
||||
<pathelement location="apps/i2psnark/java/src" />
|
||||
<pathelement location="apps/sam/java/src" />
|
||||
</sourcepath>
|
||||
<classpath>
|
||||
<pathelement location="apps/jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
|
71
checklist.txt
Normal file
71
checklist.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
Release checklist
|
||||
-----------------
|
||||
|
||||
Sync with mtn.i2p2.i2p
|
||||
Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p
|
||||
Double-check trust list
|
||||
Deploy the Jetty archive, a clean checkout lacks it
|
||||
|
||||
Change revision in:
|
||||
history.txt
|
||||
initialNews.xml
|
||||
installer/install.xml
|
||||
news.xml
|
||||
router/java/src/net/i2p/router/RouterVersion.java
|
||||
core/java/src/net/i2p/CoreVersion.java
|
||||
|
||||
Review the complete diff from the last release:
|
||||
mtn diff -r t:i2p-0.6.1.(xx-1) > out.diff
|
||||
vi out.diff
|
||||
|
||||
Build and tag:
|
||||
ant pkg
|
||||
mtn ci
|
||||
mtn tag h: i2p-0.6.1.xx
|
||||
Sync with mtn.i2p2.i2p
|
||||
|
||||
Create a signed update file with:
|
||||
export I2P=~/i2p
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign i2pupdate.zip i2pupdate.sud /path/to/private.key 0.6.1.xx
|
||||
|
||||
Verify signed update file with:
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion i2pupdate.sud
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate verifysig i2pupdate.sud
|
||||
|
||||
Make the source tarball:
|
||||
Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p i2p-0.6.1.xx
|
||||
Double-check trust list
|
||||
tar cjf i2psource-0.6.1.xx.tar.bz2 --exclude i2p-0.6.1.xx/_MTN i2p-0.6.1.xx
|
||||
mv i2p-0.6.1.xx.tar.bz2 i2p.i2p
|
||||
|
||||
Until the build script gets this ability, you need to rename some files:
|
||||
mv i2pinstall.exe i2pinstall-0.6.1.xx.exe
|
||||
mv i2p.tar.bz2 i2pheadless-0.6.1.xx.tar.bz2
|
||||
mv i2pupdate.zip i2pupdate-0.6.1.xx.zip
|
||||
you probably don't need to rename i2pupdate.sud
|
||||
|
||||
Generate hashes:
|
||||
sha1sum i2p*0.6.1.xx.*
|
||||
sha1sum i2pupdate.sud
|
||||
now GPG-sign an announcement with the hashes
|
||||
|
||||
Generate PGP signatures:
|
||||
gpg -b i2pinstall-0.6.1.xx.exe
|
||||
gpg -b i2pheadless-0.6.1.xx.tar.bz2
|
||||
gpg -b i2psource-0.6.1.xx.tar.bz2
|
||||
gpg -b i2pupdate-0.6.1.xx.zip
|
||||
gpg -b i2pupdate.sud
|
||||
|
||||
Distribute files to download locations and to www.i2p2.i2p
|
||||
|
||||
Website files to change:
|
||||
Sync with mtn.i2p2.i2p
|
||||
announcements.html
|
||||
download.html (change SHA1s)
|
||||
index.html
|
||||
hosts.txt (copy from mtn)
|
||||
Sync with mtn.i2p2.i2p
|
||||
|
||||
Copy news.xml to subscription location
|
||||
|
||||
Announce on #i2p, forum.i2p, Syndie
|
@@ -1,9 +1,27 @@
|
||||
Prior to building the jbigi library, you will need to fetch the GMP source
|
||||
from http://www.swox.com/gmp/, saving it to jbigi/gmp-4.1.4.tar.bz2 (it will
|
||||
from http://www.swox.com/gmp/, saving it to jbigi/gmp-4.2.2.tar.bz2 (it will
|
||||
be unpacked and built as necessary).
|
||||
|
||||
Version 4.2.2 has not been extensively tested with I2P. If you would like
|
||||
to use a well-tested version, get gmp-4.1.4.tar.bz2, and edit jbigi/build.sh
|
||||
to change the version number.
|
||||
|
||||
To build the native jbigi and jcpuid libraries for the current host CPU,
|
||||
simply run sh build.sh and the results will be packaged up into jbigi.jar
|
||||
and the libjbigi.so library. To test, copy jbigi/lib/libjbigi.so
|
||||
and jcpuid/lib/freenet/support/CPUInformation/libjcpuid-*.so
|
||||
to your i2p/ directory. You can also copy jbigi.jar to the i2p/lib/ directory;
|
||||
it will be used only if the router fails to load the native library.
|
||||
|
||||
To build the native jbigi libraries for all supported CPUs (on the current OS),
|
||||
go into jbigi/ and run build-all.sh (the results will be under jbigi/lib/)
|
||||
|
||||
After copying the files to the i2p/ directory,
|
||||
to run a speed test comparing the native library to the java library,
|
||||
run the shell script below.
|
||||
|
||||
-----------------
|
||||
|
||||
#!/bin/sh
|
||||
export I2P=~/i2p
|
||||
java -cp $I2P/lib/i2p.jar:$I2P/lib/jbigi.jar net.i2p.util.NativeBigInteger
|
||||
|
0
core/c/build.sh
Normal file → Executable file
0
core/c/build.sh
Normal file → Executable file
7
core/c/jbigi/build-all.sh
Normal file → Executable file
7
core/c/jbigi/build-all.sh
Normal file → Executable file
@@ -12,8 +12,9 @@ FreeBSD*)
|
||||
exit;;
|
||||
esac
|
||||
|
||||
echo "Extracting GMP..."
|
||||
tar -xjf gmp-4.1.4.tar.bz2
|
||||
VER=4.2.2
|
||||
echo "Extracting GMP Version $VER ..."
|
||||
tar -xjf gmp-$VER.tar.bz2
|
||||
echo "Building..."
|
||||
mkdir bin
|
||||
mkdir lib
|
||||
@@ -24,7 +25,7 @@ for x in none pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon
|
||||
do
|
||||
mkdir bin/$x
|
||||
cd bin/$x
|
||||
../../gmp-4.1.4/configure --build=$x
|
||||
../../gmp-$VER/configure --build=$x
|
||||
make
|
||||
sh ../../build_jbigi.sh static
|
||||
case `uname -sr` in
|
||||
|
9
core/c/jbigi/build.sh
Normal file → Executable file
9
core/c/jbigi/build.sh
Normal file → Executable file
@@ -1,9 +1,10 @@
|
||||
#/bin/sh
|
||||
|
||||
echo "Building the jbigi library with GMP"
|
||||
VER=4.2.2
|
||||
echo "Building the jbigi library with GMP Version $VER"
|
||||
|
||||
echo "Extracting GMP..."
|
||||
tar -xjf gmp-4.1.4.tar.bz2
|
||||
tar -xjf gmp-$VER.tar.bz2
|
||||
echo "Building..."
|
||||
mkdir -p lib/
|
||||
mkdir -p bin/local
|
||||
@@ -11,9 +12,9 @@ cd bin/local
|
||||
case `uname -sr` in
|
||||
Darwin*)
|
||||
# --with-pic is required for static linking
|
||||
../../gmp-4.1.4/configure --with-pic;;
|
||||
../../gmp-$VER/configure --with-pic;;
|
||||
*)
|
||||
../../gmp-4.1.4/configure;;
|
||||
../../gmp-$VER/configure;;
|
||||
esac
|
||||
make
|
||||
sh ../../build_jbigi.sh static
|
||||
|
0
core/c/jbigi/build_jbigi.sh
Normal file → Executable file
0
core/c/jbigi/build_jbigi.sh
Normal file → Executable file
0
core/c/jcpuid/build.sh
Normal file → Executable file
0
core/c/jcpuid/build.sh
Normal file → Executable file
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
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 final static String ID = "$Revision: 1.72 $ $Date: 2007-08-23 19:33:31 $";
|
||||
public final static String VERSION = "0.6.1.33";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
146
core/java/src/net/i2p/client/naming/EepGetNamingService.java
Normal file
146
core/java/src/net/i2p/client/naming/EepGetNamingService.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* By zzz 2008, released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
*/
|
||||
package net.i2p.client.naming;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* A network-based naming service using HTTP, with in-memory caching.
|
||||
* Fetches from one or more remote (in-i2p) CGI services using HTTP GET.
|
||||
*
|
||||
* The remote HTTP service takes a CGI parameter and must return (only) the
|
||||
* 516-byte Base64 destination, or hostname=dest.
|
||||
* A trailing \n or \r\n is acceptable.
|
||||
*
|
||||
* Should be used from MetaNamingService, after HostsTxtNamingService.
|
||||
* Cannot be used as the only NamingService! Be sure any naming service hosts
|
||||
* are in hosts.txt.
|
||||
*
|
||||
* Sample config to put in configadvanced.jsp (restart required):
|
||||
*
|
||||
* i2p.naming.impl=net.i2p.client.naming.MetaNamingService
|
||||
* i2p.nameservicelist=net.i2p.client.naming.HostsTxtNamingService,net.i2p.client.naming.EepGetNamingService
|
||||
* i2p.naming.eepget.list=http://namingservice.i2p/cgi-bin/lkup.cgi?host=,http://i2host.i2p/cgi-bin/i2hostquery?
|
||||
*
|
||||
*/
|
||||
public class EepGetNamingService extends NamingService {
|
||||
|
||||
private final static String PROP_EEPGET_LIST = "i2p.naming.eepget.list";
|
||||
private final static String DEFAULT_EEPGET_LIST = "http://i2host.i2p/cgi-bin/i2hostquery?";
|
||||
private static Properties _hosts;
|
||||
private final static Log _log = new Log(EepGetNamingService.class);
|
||||
|
||||
/**
|
||||
* The naming service should only be constructed and accessed through the
|
||||
* application context. This constructor should only be used by the
|
||||
* appropriate application context itself.
|
||||
*
|
||||
*/
|
||||
public EepGetNamingService(I2PAppContext context) {
|
||||
super(context);
|
||||
_hosts = new Properties();
|
||||
}
|
||||
|
||||
private List getURLs() {
|
||||
String list = _context.getProperty(PROP_EEPGET_LIST, DEFAULT_EEPGET_LIST);
|
||||
StringTokenizer tok = new StringTokenizer(list, ",");
|
||||
List rv = new ArrayList(tok.countTokens());
|
||||
while (tok.hasMoreTokens())
|
||||
rv.add(tok.nextToken());
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Destination lookup(String hostname) {
|
||||
// If it's long, assume it's a key.
|
||||
if (hostname.length() >= DEST_SIZE)
|
||||
return lookupBase64(hostname);
|
||||
|
||||
hostname = hostname.toLowerCase();
|
||||
|
||||
// check the cache
|
||||
String key = _hosts.getProperty(hostname);
|
||||
if (key != null) {
|
||||
_log.error("Found in cache: " + hostname);
|
||||
return lookupBase64(key);
|
||||
}
|
||||
|
||||
List URLs = getURLs();
|
||||
if (URLs.size() == 0)
|
||||
return null;
|
||||
|
||||
// prevent lookup loops - this cannot be the only lookup service
|
||||
for (int i = 0; i < URLs.size(); i++) {
|
||||
String url = (String)URLs.get(i);
|
||||
if (url.startsWith("http://" + hostname + "/")) {
|
||||
_log.error("Lookup loop: " + hostname);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// lookup
|
||||
for (int i = 0; i < URLs.size(); i++) {
|
||||
String url = (String)URLs.get(i);
|
||||
key = fetchAddr(url, hostname);
|
||||
if (key != null) {
|
||||
_log.error("Success: " + url + hostname);
|
||||
_hosts.setProperty(hostname, key); // cache
|
||||
return lookupBase64(key);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
|
||||
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
|
||||
private String fetchAddr(String url, String hostname) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(MAX_RESPONSE);
|
||||
|
||||
try {
|
||||
// Do a proxied eepget into our ByteArrayOutputStream with 0 retries
|
||||
EepGet get = new EepGet(_context, true, "localhost", 4444, 0, DEST_SIZE, MAX_RESPONSE,
|
||||
null, baos, url + hostname, false, null, null);
|
||||
// 10s header timeout, 15s total timeout, unlimited inactivity timeout
|
||||
if (get.fetch(10*1000l, 15*1000l, -1l)) {
|
||||
if (baos.size() < DEST_SIZE) {
|
||||
_log.error("Short response: " + url + hostname);
|
||||
return null;
|
||||
}
|
||||
String key = baos.toString();
|
||||
if (key.startsWith(hostname + "=")) // strip hostname=
|
||||
key = key.substring(hostname.length() + 1);
|
||||
key = key.substring(0, DEST_SIZE); // catch IndexOutOfBounds exception below
|
||||
if (!key.endsWith("AAAA")) {
|
||||
_log.error("Invalid key: " + url + hostname);
|
||||
return null;
|
||||
}
|
||||
if (key.replaceAll("[a-zA-Z0-9~-]", "").length() != 0) {
|
||||
_log.error("Invalid chars: " + url + hostname);
|
||||
return null;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
_log.error("Fetch failed from: " + url + hostname);
|
||||
return null;
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error fetching the addr", t);
|
||||
}
|
||||
_log.error("Caught from: " + url + hostname);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String reverseLookup(Destination dest) {
|
||||
return null;
|
||||
}
|
||||
}
|
137
core/java/src/net/i2p/client/naming/ExecNamingService.java
Normal file
137
core/java/src/net/i2p/client/naming/ExecNamingService.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* By zzz 2008, released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
*/
|
||||
package net.i2p.client.naming;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Exec;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* An interface to an external naming service program, with in-memory caching.
|
||||
* This can be used as a simple and flexible way to experiment with
|
||||
* alternative naming systems.
|
||||
*
|
||||
* The external command takes a hostname argument and must return (only) the
|
||||
* 516-byte Base64 destination, or hostname=dest, on stdout.
|
||||
* A trailing \n or \r\n is acceptable.
|
||||
* The command must exit 0 on success. Nonzero on failure is optional.
|
||||
*
|
||||
* The external command can do local and/or remote (via i2p or not) lookups.
|
||||
* No timeouts are implemented here - the author of the external program
|
||||
* must ensure that the program returns in a reasonable amount of time -
|
||||
* (15 sec max suggested)
|
||||
*
|
||||
* Can be used from MetaNamingService, (e.g. after HostsTxtNamingService),
|
||||
* or as the sole naming service.
|
||||
*
|
||||
* Sample chained config to put in configadvanced.jsp (restart required):
|
||||
*
|
||||
* i2p.naming.impl=net.i2p.client.naming.MetaNamingService
|
||||
* i2p.nameservicelist=net.i2p.client.naming.HostsTxtNamingService,net.i2p.client.naming.ExecNamingService
|
||||
* i2p.naming.exec.command=/usr/local/bin/i2presolve
|
||||
*
|
||||
* Sample unchained config to put in configadvanced.jsp (restart required):
|
||||
*
|
||||
* i2p.naming.impl=net.i2p.client.naming.ExecNamingService
|
||||
* i2p.naming.exec.command=/usr/local/bin/i2presolve
|
||||
*
|
||||
*/
|
||||
public class ExecNamingService extends NamingService {
|
||||
|
||||
private final static String PROP_EXEC_CMD = "i2p.naming.exec.command";
|
||||
private final static String DEFAULT_EXEC_CMD = "/usr/local/bin/i2presolve";
|
||||
private final static String PROP_SHELL_CMD = "i2p.naming.exec.shell";
|
||||
private final static String DEFAULT_SHELL_CMD = "/bin/bash";
|
||||
private static Properties _hosts;
|
||||
private final static Log _log = new Log(ExecNamingService.class);
|
||||
|
||||
/**
|
||||
* The naming service should only be constructed and accessed through the
|
||||
* application context. This constructor should only be used by the
|
||||
* appropriate application context itself.
|
||||
*
|
||||
*/
|
||||
public ExecNamingService(I2PAppContext context) {
|
||||
super(context);
|
||||
_hosts = new Properties();
|
||||
}
|
||||
|
||||
public Destination lookup(String hostname) {
|
||||
// If it's long, assume it's a key.
|
||||
if (hostname.length() >= DEST_SIZE)
|
||||
return lookupBase64(hostname);
|
||||
|
||||
hostname = hostname.toLowerCase();
|
||||
|
||||
// check the cache
|
||||
String key = _hosts.getProperty(hostname);
|
||||
if (key != null) {
|
||||
_log.error("Found in cache: " + hostname);
|
||||
return lookupBase64(key);
|
||||
}
|
||||
|
||||
// lookup
|
||||
key = fetchAddr(hostname);
|
||||
if (key != null) {
|
||||
_log.error("Success: " + hostname);
|
||||
_hosts.setProperty(hostname, key); // cache
|
||||
return lookupBase64(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
|
||||
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
|
||||
private String fetchAddr(String hostname) {
|
||||
String[] commandArr = new String[3];
|
||||
commandArr[0] = _context.getProperty(PROP_SHELL_CMD, DEFAULT_SHELL_CMD);
|
||||
commandArr[1] = "-c";
|
||||
String command = _context.getProperty(PROP_EXEC_CMD, DEFAULT_EXEC_CMD) + " " + hostname;
|
||||
commandArr[2] = command;
|
||||
|
||||
try {
|
||||
Process get = Runtime.getRuntime().exec(commandArr);
|
||||
get.waitFor();
|
||||
int exitValue = get.exitValue();
|
||||
if (exitValue != 0) {
|
||||
_log.error("Exit " + exitValue + " from " + commandArr[0] + " " + commandArr[1] + " \"" + command + "\"");
|
||||
return null;
|
||||
}
|
||||
InputStream is = get.getInputStream();
|
||||
byte[] input = new byte[MAX_RESPONSE];
|
||||
int count = is.read(input);
|
||||
is.close();
|
||||
if (count < DEST_SIZE) {
|
||||
_log.error("Short response: " + command);
|
||||
return null;
|
||||
}
|
||||
String key = new String(input);
|
||||
if (key.startsWith(hostname + "=")) // strip hostname=
|
||||
key = key.substring(hostname.length() + 1);
|
||||
key = key.substring(0, DEST_SIZE); // catch IndexOutOfBounds exception below
|
||||
if (!key.endsWith("AAAA")) {
|
||||
_log.error("Invalid key: " + command);
|
||||
return null;
|
||||
}
|
||||
if (key.replaceAll("[a-zA-Z0-9~-]", "").length() != 0) {
|
||||
_log.error("Invalid chars: " + command);
|
||||
return null;
|
||||
}
|
||||
return key;
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error fetching the addr", t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String reverseLookup(Destination dest) {
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -9,8 +9,10 @@ package net.i2p.client.naming;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
@@ -54,6 +56,10 @@ public class HostsTxtNamingService extends NamingService {
|
||||
}
|
||||
|
||||
public Destination lookup(String hostname) {
|
||||
// If it's long, assume it's a key.
|
||||
if (hostname.length() >= 516)
|
||||
return lookupBase64(hostname);
|
||||
|
||||
// check the list each time, reloading the file on each
|
||||
// lookup
|
||||
|
||||
@@ -79,12 +85,32 @@ public class HostsTxtNamingService extends NamingService {
|
||||
}
|
||||
// not found, continue to the next file
|
||||
}
|
||||
// If we can't find name in any of the hosts files,
|
||||
// assume it's a key.
|
||||
return lookupBase64(hostname);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String reverseLookup(Destination dest) {
|
||||
String destkey = dest.toBase64();
|
||||
List filenames = getFilenames();
|
||||
for (int i = 0; i < filenames.size(); i++) {
|
||||
String hostsfile = (String)filenames.get(i);
|
||||
Properties hosts = new Properties();
|
||||
try {
|
||||
File f = new File(hostsfile);
|
||||
if ( (f.exists()) && (f.canRead()) ) {
|
||||
DataHelper.loadProps(hosts, f, true);
|
||||
Set keyset = hosts.keySet();
|
||||
Iterator iter = keyset.iterator();
|
||||
while (iter.hasNext()) {
|
||||
String host = (String)iter.next();
|
||||
String key = hosts.getProperty(host);
|
||||
if (destkey.equals(key))
|
||||
return host;
|
||||
}
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
_log.error("Error loading hosts file " + hostsfile, ioe);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ public abstract class NamingService {
|
||||
|
||||
/** what classname should be used as the naming service impl? */
|
||||
public static final String PROP_IMPL = "i2p.naming.impl";
|
||||
private static final String DEFAULT_IMPL = "net.i2p.client.naming.MetaNamingService";
|
||||
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService";
|
||||
|
||||
|
||||
/**
|
||||
@@ -89,4 +89,4 @@ public abstract class NamingService {
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -60,6 +60,45 @@ jP69nPbh4KLGhF+SD0+0bW4=
|
||||
=npPe
|
||||
-----END PGP SIGNATURE-----
|
||||
*/
|
||||
/*
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
*/
|
||||
/* zzz's key */
|
||||
private static final String DEFAULT_TRUSTED_KEY2 =
|
||||
"lT54eq3SH0TWWwQ1wgH6XPelIno7wH7UfiZOpQg-ZuxdNhc4UjjrohKdK" +
|
||||
"Zqfswt1ANPnmOlMewLGBESl7kJB9c5sByz~IOlNyz5BMLRC~R~ZC9QI4W" +
|
||||
"XwUBYW8BhYO2mkvtdOrcy690lDkwzdf5xLxlCBpQlTaLYzQVjVWBcvbCA=";
|
||||
/*
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFHdupcQVV2uqduC+0RAocuAKCR4ILLuz3RB8QT7zkadmS2LmFuMwCgweqG
|
||||
lFm5Fqx/iW5+k0QaQZ3W9mY=
|
||||
=V3i7
|
||||
-----END PGP SIGNATURE-----
|
||||
*/
|
||||
/*
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
*/
|
||||
/* Complication's key */
|
||||
private static final String DEFAULT_TRUSTED_KEY3 =
|
||||
"JHFA0yXUgKtmhajXFZH9Nk62OPRHbvvQHTi8EANV-D~3tjLjaz9p9cs6F" +
|
||||
"s8W3FSLfUwsQeFg7dfVSQQZga~1jMjboo94vIcm3j6XbW4mbcorVQ74uP" +
|
||||
"jd8EA1AQhJ6bBTxDAFk~6fVDOdhHT0Wo5CcUn7v8bAYY3x3UWiL8Remx0=";
|
||||
/*
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFHphOV+h38a3n8zjMRAll+AJ9KA6WiDJcTN4qfrslSemUMr+FBrwCeM8pF
|
||||
D8usM7Dxp5yrDrCYZ5AIijc=
|
||||
=SrXI
|
||||
-----END PGP SIGNATURE-----
|
||||
*/
|
||||
|
||||
private static final String VALID_VERSION_CHARS = "0123456789.";
|
||||
private static final int VERSION_BYTES = 16;
|
||||
private static final int HEADER_BYTES = Signature.SIGNATURE_BYTES + VERSION_BYTES;
|
||||
@@ -92,14 +131,18 @@ jP69nPbh4KLGhF+SD0+0bW4=
|
||||
String propertyTrustedKeys = context.getProperty(PROP_TRUSTED_KEYS);
|
||||
|
||||
if ( (propertyTrustedKeys != null) && (propertyTrustedKeys.length() > 0) ) {
|
||||
StringTokenizer propertyTrustedKeysTokens = new StringTokenizer(propertyTrustedKeys, ",");
|
||||
StringTokenizer propertyTrustedKeysTokens = new StringTokenizer(propertyTrustedKeys, " ,\r\n");
|
||||
|
||||
while (propertyTrustedKeysTokens.hasMoreTokens())
|
||||
_trustedKeys.add(propertyTrustedKeysTokens.nextToken().trim());
|
||||
|
||||
} else {
|
||||
_trustedKeys.add(DEFAULT_TRUSTED_KEY);
|
||||
_trustedKeys.add(DEFAULT_TRUSTED_KEY2);
|
||||
_trustedKeys.add(DEFAULT_TRUSTED_KEY3);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("TrustedUpdate created, trusting " + _trustedKeys.size() + " keys.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,6 +223,7 @@ jP69nPbh4KLGhF+SD0+0bW4=
|
||||
private static final void genKeysCLI(String publicKeyFile, String privateKeyFile) {
|
||||
FileOutputStream fileOutputStream = null;
|
||||
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
try {
|
||||
Object signingKeypair[] = _context.keyGenerator().generateSigningKeypair();
|
||||
SigningPublicKey signingPublicKey = (SigningPublicKey) signingKeypair[0];
|
||||
@@ -273,7 +317,26 @@ jP69nPbh4KLGhF+SD0+0bW4=
|
||||
public ArrayList getTrustedKeys() {
|
||||
return _trustedKeys;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the trusted keys for the current instance.
|
||||
*
|
||||
* @return A <code>String</code> containing the trusted keys,
|
||||
* delimited by CR LF line breaks.
|
||||
*/
|
||||
public String getTrustedKeysString() {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
for (int i = 0; i < _trustedKeys.size(); i++) {
|
||||
// If something already buffered, first add line break.
|
||||
if (buf.length() > 0) buf.append("\r\n");
|
||||
buf.append((String) _trustedKeys.get(i));
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the version string from a signed update file.
|
||||
*
|
||||
|
@@ -236,6 +236,10 @@ public class DataHelper {
|
||||
if (split <= 0) continue;
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1);
|
||||
// Unescape line breaks after loading.
|
||||
// Remember: "\" needs escaping both for regex and string.
|
||||
val = val.replaceAll("\\\\r","\r");
|
||||
val = val.replaceAll("\\\\n","\n");
|
||||
if ( (key.length() > 0) && (val.length() > 0) )
|
||||
if (forceLowerCase)
|
||||
props.setProperty(key.toLowerCase(), val);
|
||||
@@ -826,7 +830,7 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
public static String formatDuration(long ms) {
|
||||
if (ms < 30 * 1000) {
|
||||
if (ms < 5 * 1000) {
|
||||
return ms + "ms";
|
||||
} else if (ms < 5 * 60 * 1000) {
|
||||
return (ms / 1000) + "s";
|
||||
|
@@ -32,6 +32,25 @@ public class StatManager {
|
||||
public static final String PROP_STAT_FILTER = "stat.logFilters";
|
||||
public static final String PROP_STAT_FILE = "stat.logFile";
|
||||
public static final String DEFAULT_STAT_FILE = "stats.log";
|
||||
public static final String PROP_STAT_FULL = "stat.full";
|
||||
public static final String DEFAULT_STAT_FULL = "true";
|
||||
public static final String PROP_STAT_REQUIRED = "stat.required";
|
||||
/**
|
||||
* These are all the stats published in netDb, plus those required for the operation of
|
||||
* the router (many in RouterThrottleImpl), plus those that are on graphs.jsp by default.
|
||||
* Wildcard ('*') allowed at end of stat only.
|
||||
* Ignore all the rest of the stats unless stat.full=true.
|
||||
*/
|
||||
public static final String DEFAULT_STAT_REQUIRED =
|
||||
"bw.recvRate,bw.sendBps,bw.sendRate,client.sendAckTime,clock.skew,crypto.elGamal.encrypt," +
|
||||
"jobQueue.jobLag,netDb.successTime,router.fastPeers," +
|
||||
"transport.receiveMessageSize,transport.sendMessageSize,transport.sendProcessingTime," +
|
||||
"tunnel.acceptLoad,tunnel.buildRequestTime,tunnel.rejectOverloaded,tunnel.rejectTimeout" +
|
||||
"tunnel.buildClientExpire,tunnel.buildClientReject,tunnel.buildClientSuccess," +
|
||||
"tunnel.buildExploratoryExpire,tunnel.buildExploratoryReject,tunnel.buildExploratorySuccess," +
|
||||
"tunnel.buildRatio.*,tunnel.buildFailure,tunnel.buildSuccess,tunnel.corruptMessage," +
|
||||
"tunnel.decryptRequestTime,tunnel.fragmentedDropped,tunnel.participatingMessageCount,"+
|
||||
"tunnel.participatingTunnels,tunnel.testFailedTime,tunnel.testSuccessTime" ;
|
||||
|
||||
/**
|
||||
* The stat manager should only be constructed and accessed through the
|
||||
@@ -67,6 +86,7 @@ public class StatManager {
|
||||
* @param periods array of period lengths (in milliseconds)
|
||||
*/
|
||||
public void createFrequencyStat(String name, String description, String group, long periods[]) {
|
||||
if (ignoreStat(name)) return;
|
||||
if (_frequencyStats.containsKey(name)) return;
|
||||
_frequencyStats.put(name, new FrequencyStat(name, description, group, periods));
|
||||
}
|
||||
@@ -80,6 +100,7 @@ public class StatManager {
|
||||
* @param periods array of period lengths (in milliseconds)
|
||||
*/
|
||||
public void createRateStat(String name, String description, String group, long periods[]) {
|
||||
if (ignoreStat(name)) return;
|
||||
synchronized (_rateStats) {
|
||||
if (_rateStats.containsKey(name)) return;
|
||||
RateStat rs = new RateStat(name, description, group, periods);
|
||||
@@ -165,4 +186,20 @@ public class StatManager {
|
||||
|
||||
public String getStatFilter() { return _context.getProperty(PROP_STAT_FILTER); }
|
||||
public String getStatFile() { return _context.getProperty(PROP_STAT_FILE, DEFAULT_STAT_FILE); }
|
||||
|
||||
// Save memory by not creating stats unless they are required for router operation
|
||||
// Return true if the stat should be ignored.
|
||||
public boolean ignoreStat(String statName) {
|
||||
if (_context.getProperty(PROP_STAT_FULL, DEFAULT_STAT_FULL).equalsIgnoreCase("true"))
|
||||
return false;
|
||||
String required = _context.getProperty(PROP_STAT_REQUIRED, DEFAULT_STAT_REQUIRED);
|
||||
String req[] = required.split(",");
|
||||
for (int i=0; i<req.length; i++) {
|
||||
if (req[i].equals(statName))
|
||||
return false;
|
||||
if (req[i].endsWith("*") && statName.startsWith(req[i].substring(0, req[i].length() - 2)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.SocketTimeout;
|
||||
|
||||
/**
|
||||
* EepGet [-p localhost:4444]
|
||||
@@ -37,7 +38,10 @@ public class EepGet {
|
||||
private long _maxSize; // applied both against whole responses and chunks
|
||||
private String _outputFile;
|
||||
private OutputStream _outputStream;
|
||||
/** url we were asked to fetch */
|
||||
private String _url;
|
||||
/** the URL we actually fetch from (may differ from the _url in case of redirect) */
|
||||
private String _actualURL;
|
||||
private String _postData;
|
||||
private boolean _allowCaching;
|
||||
private List _listeners;
|
||||
@@ -52,45 +56,52 @@ public class EepGet {
|
||||
private long _bytesRemaining;
|
||||
private int _currentAttempt;
|
||||
private String _etag;
|
||||
private String _lastModified;
|
||||
private boolean _encodingChunked;
|
||||
private boolean _notModified;
|
||||
private String _contentType;
|
||||
private boolean _transferFailed;
|
||||
private boolean _headersRead;
|
||||
private boolean _aborted;
|
||||
private long _fetchHeaderTimeout;
|
||||
private long _fetchEndTime;
|
||||
private long _fetchInactivityTimeout;
|
||||
private int _redirects;
|
||||
private String _redirectLocation;
|
||||
|
||||
// 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, -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, -1, -1, outputFile, null, url, allowCaching, etag, null);
|
||||
}
|
||||
// Constructor 0, real constructor
|
||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag, String lastModified) {
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, lastModified, null);
|
||||
}
|
||||
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) {
|
||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, minSize, maxSize, outputFile, outputStream, url, allowCaching, etag, null, postData);
|
||||
}
|
||||
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) {
|
||||
String etag, String lastModified, String postData) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(EepGet.class);
|
||||
_shouldProxy = shouldProxy;
|
||||
_shouldProxy = (proxyHost != null) && (proxyHost.length() > 0) && (proxyPort > 0) && shouldProxy;
|
||||
_proxyHost = proxyHost;
|
||||
_proxyPort = proxyPort;
|
||||
_numRetries = numRetries;
|
||||
@@ -99,13 +110,19 @@ public class EepGet {
|
||||
_outputFile = outputFile; // if outputFile is set, outputStream must be null
|
||||
_outputStream = outputStream; // if both are set, outputStream overrides outputFile
|
||||
_url = url;
|
||||
_actualURL = url;
|
||||
_postData = postData;
|
||||
_alreadyTransferred = 0;
|
||||
_bytesTransferred = 0;
|
||||
_bytesRemaining = -1;
|
||||
_currentAttempt = 0;
|
||||
_transferFailed = false;
|
||||
_headersRead = false;
|
||||
_aborted = false;
|
||||
_fetchHeaderTimeout = 45*1000;
|
||||
_listeners = new ArrayList(1);
|
||||
_etag = etag;
|
||||
_lastModified = lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,18 +215,35 @@ public class EepGet {
|
||||
}
|
||||
|
||||
public static interface StatusListener {
|
||||
/**
|
||||
* alreadyTransferred - total of all attempts, not including currentWrite
|
||||
* If nonzero on the first call, a partial file of that length was found
|
||||
* To track _actual_ transfer if the output file could already exist,
|
||||
* the listener should keep its own counter,
|
||||
* or subtract the initial alreadyTransferred value.
|
||||
* currentWrite - since last call to the listener
|
||||
* bytesTransferred - includes headers, retries, redirects, ...
|
||||
* bytesRemaining - on this attempt only, currentWrite already subtracted -
|
||||
* or -1 if chunked encoding or server does not return a length
|
||||
*
|
||||
* Total length should be == alreadyTransferred + currentWrite + bytesRemaining for all calls
|
||||
*
|
||||
*/
|
||||
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 attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause);
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt);
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val);
|
||||
public void attempting(String url);
|
||||
}
|
||||
private class CLIStatusListener implements StatusListener {
|
||||
private int _markSize;
|
||||
private int _lineSize;
|
||||
private long _startedOn;
|
||||
private long _written;
|
||||
private long _previousWritten;
|
||||
private long _lastComplete;
|
||||
private boolean _firstTime;
|
||||
private DecimalFormat _pct = new DecimalFormat("00.0%");
|
||||
private DecimalFormat _kbps = new DecimalFormat("###,000.00");
|
||||
public CLIStatusListener() {
|
||||
@@ -219,10 +253,19 @@ public class EepGet {
|
||||
_markSize = markSize;
|
||||
_lineSize = lineSize;
|
||||
_written = 0;
|
||||
_previousWritten = 0;
|
||||
_lastComplete = _context.clock().now();
|
||||
_startedOn = _lastComplete;
|
||||
_firstTime = true;
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
if (_firstTime) {
|
||||
if (alreadyTransferred > 0) {
|
||||
_previousWritten = alreadyTransferred;
|
||||
System.out.println("File found with length " + alreadyTransferred + ", resuming");
|
||||
}
|
||||
_firstTime = false;
|
||||
}
|
||||
for (int i = 0; i < currentWrite; i++) {
|
||||
_written++;
|
||||
if ( (_markSize > 0) && (_written % _markSize == 0) ) {
|
||||
@@ -235,13 +278,14 @@ public class EepGet {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append(" ");
|
||||
if ( bytesRemaining > 0 ) {
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
double pct = ((double)_written + _previousWritten) /
|
||||
((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
}
|
||||
buf.append(": ");
|
||||
}
|
||||
buf.append(_written+alreadyTransferred);
|
||||
buf.append(_written);
|
||||
buf.append(" @ ");
|
||||
double lineKBytes = ((double)_markSize * (double)_lineSize)/1024.0d;
|
||||
double kbps = lineKBytes/((double)timeToSend/1000.0d);
|
||||
@@ -252,7 +296,7 @@ public class EepGet {
|
||||
|
||||
buf.append(" / ");
|
||||
long lifetime = _context.clock().now() - _startedOn;
|
||||
double lifetimeKBps = (1000.0d*(double)(_written+alreadyTransferred)/((double)lifetime*1024.0d));
|
||||
double lifetimeKBps = (1000.0d*(double)(_written)/((double)lifetime*1024.0d));
|
||||
synchronized (_kbps) {
|
||||
buf.append(_kbps.format(lifetimeKBps));
|
||||
}
|
||||
@@ -265,32 +309,40 @@ public class EepGet {
|
||||
}
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
long transferred;
|
||||
if (_firstTime)
|
||||
transferred = 0;
|
||||
else
|
||||
transferred = alreadyTransferred - _previousWritten;
|
||||
System.out.println();
|
||||
System.out.println("== " + new Date());
|
||||
if (notModified) {
|
||||
System.out.println("== Source not modified since last download");
|
||||
} else {
|
||||
if ( bytesRemaining > 0 ) {
|
||||
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
|
||||
+ " and " + (bytesRemaining - bytesTransferred) + " remaining");
|
||||
System.out.println("== Output saved to " + outputFile);
|
||||
System.out.println("== Transfer of " + url + " completed with " + transferred
|
||||
+ " transferred and " + (bytesRemaining - bytesTransferred) + " remaining");
|
||||
} else {
|
||||
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
|
||||
System.out.println("== Transfer of " + url + " completed with " + transferred
|
||||
+ " bytes transferred");
|
||||
System.out.println("== Output saved to " + outputFile);
|
||||
}
|
||||
if (transferred > 0)
|
||||
System.out.println("== Output saved to " + outputFile + " (" + alreadyTransferred + " bytes)");
|
||||
}
|
||||
long timeToSend = _context.clock().now() - _startedOn;
|
||||
System.out.println("== Transfer time: " + DataHelper.formatDuration(timeToSend));
|
||||
System.out.println("== ETag: " + _etag);
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("== Transfer rate: ");
|
||||
double kbps = (1000.0d*(double)(_written)/((double)timeToSend*1024.0d));
|
||||
synchronized (_kbps) {
|
||||
buf.append(_kbps.format(kbps));
|
||||
if (_etag != null)
|
||||
System.out.println("== ETag: " + _etag);
|
||||
if (transferred > 0) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("== Transfer rate: ");
|
||||
double kbps = (1000.0d*(double)(transferred)/((double)timeToSend*1024.0d));
|
||||
synchronized (_kbps) {
|
||||
buf.append(_kbps.format(kbps));
|
||||
}
|
||||
buf.append("KBps");
|
||||
System.out.println(buf.toString());
|
||||
}
|
||||
buf.append("KBps");
|
||||
System.out.println(buf.toString());
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
System.out.println();
|
||||
@@ -299,6 +351,7 @@ public class EepGet {
|
||||
System.out.println("** Transfered " + bytesTransferred
|
||||
+ " with " + (bytesRemaining < 0 ? "unknown" : ""+bytesRemaining) + " remaining");
|
||||
System.out.println("** " + cause.getMessage());
|
||||
_previousWritten += _written;
|
||||
_written = 0;
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
@@ -317,6 +370,7 @@ public class EepGet {
|
||||
buf.append("KBps");
|
||||
System.out.println(buf.toString());
|
||||
}
|
||||
public void attempting(String url) {}
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
||||
}
|
||||
|
||||
@@ -329,19 +383,52 @@ public class EepGet {
|
||||
* Blocking fetch, returning true if the URL was retrieved, false if all retries failed
|
||||
*
|
||||
*/
|
||||
public boolean fetch() {
|
||||
public boolean fetch() { return fetch(_fetchHeaderTimeout); }
|
||||
/**
|
||||
* Blocking fetch, timing out individual attempts if the HTTP response headers
|
||||
* don't come back in the time given. If the timeout is zero or less, this will
|
||||
* wait indefinitely.
|
||||
*/
|
||||
public boolean fetch(long fetchHeaderTimeout) {
|
||||
return fetch(fetchHeaderTimeout, -1, -1);
|
||||
}
|
||||
public boolean fetch(long fetchHeaderTimeout, long totalTimeout, long inactivityTimeout) {
|
||||
_fetchHeaderTimeout = fetchHeaderTimeout;
|
||||
_fetchEndTime = (totalTimeout > 0 ? System.currentTimeMillis() + totalTimeout : -1);
|
||||
_fetchInactivityTimeout = inactivityTimeout;
|
||||
_keepFetching = true;
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _url);
|
||||
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _actualURL);
|
||||
while (_keepFetching) {
|
||||
SocketTimeout timeout = null;
|
||||
if (_fetchHeaderTimeout > 0)
|
||||
timeout = new SocketTimeout(_fetchHeaderTimeout);
|
||||
final SocketTimeout stimeout = timeout; // ugly
|
||||
timeout.setTimeoutCommand(new Runnable() {
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("timeout reached on " + _url + ": " + stimeout);
|
||||
_aborted = true;
|
||||
}
|
||||
});
|
||||
timeout.setTotalTimeoutPeriod(_fetchEndTime);
|
||||
try {
|
||||
sendRequest();
|
||||
doFetch();
|
||||
return true;
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).attempting(_url);
|
||||
sendRequest(timeout);
|
||||
timeout.resetTimer();
|
||||
doFetch(timeout);
|
||||
timeout.cancel();
|
||||
if (!_transferFailed)
|
||||
return true;
|
||||
break;
|
||||
} catch (IOException ioe) {
|
||||
timeout.cancel();
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("ERR: doFetch failed " + ioe);
|
||||
} finally {
|
||||
if (_out != null) {
|
||||
try {
|
||||
@@ -360,51 +447,120 @@ public class EepGet {
|
||||
_currentAttempt++;
|
||||
if (_currentAttempt > _numRetries)
|
||||
break;
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
try {
|
||||
long delay = _context.random().nextInt(60*1000);
|
||||
Thread.sleep(5*1000+delay);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).transferFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("All attempts failed for " + _url);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** a single fetch attempt */
|
||||
private void doFetch() throws IOException {
|
||||
readHeaders();
|
||||
/** return true if the URL was completely retrieved */
|
||||
private void doFetch(SocketTimeout timeout) throws IOException {
|
||||
_headersRead = false;
|
||||
_aborted = false;
|
||||
try {
|
||||
readHeaders();
|
||||
} finally {
|
||||
_headersRead = true;
|
||||
}
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP headers");
|
||||
|
||||
timeout.resetTimer();
|
||||
if (_fetchInactivityTimeout > 0)
|
||||
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||
else
|
||||
timeout.setInactivityTimeout(60*1000);
|
||||
|
||||
if (_redirectLocation != null) {
|
||||
try {
|
||||
URL oldURL = new URL(_actualURL);
|
||||
String query = oldURL.getQuery();
|
||||
if (query == null) query = "";
|
||||
if (_redirectLocation.startsWith("http://")) {
|
||||
if ( (_redirectLocation.indexOf('?') < 0) && (query.length() > 0) )
|
||||
_actualURL = _redirectLocation + "?" + query;
|
||||
else
|
||||
_actualURL = _redirectLocation;
|
||||
} else {
|
||||
URL url = new URL(_actualURL);
|
||||
if (_redirectLocation.startsWith("/"))
|
||||
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation;
|
||||
else
|
||||
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation;
|
||||
if ( (_actualURL.indexOf('?') < 0) && (query.length() > 0) )
|
||||
_actualURL = _actualURL + "?" + query;
|
||||
else
|
||||
_actualURL = _actualURL;
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
throw new IOException("Redirected from an invalid URL");
|
||||
}
|
||||
_redirects++;
|
||||
if (_redirects > 5)
|
||||
throw new IOException("Too many redirects: to " + _redirectLocation);
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation);
|
||||
sendRequest(timeout);
|
||||
doFetch(timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
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))
|
||||
if ((_minSize > 0) && (_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 )) {
|
||||
while (_keepFetching && ( (remaining > 0) || !strictSize ) && !_aborted) {
|
||||
int toRead = buf.length;
|
||||
if (strictSize && toRead > remaining)
|
||||
toRead = remaining;
|
||||
int read = _proxyIn.read(buf, 0, toRead);
|
||||
if (read == -1)
|
||||
break;
|
||||
timeout.resetTimer();
|
||||
_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;
|
||||
if ((_maxSize > -1) && (_alreadyTransferred + read > _maxSize)) // could transfer a little over maxSize
|
||||
throw new IOException("Bytes transferred " + (_alreadyTransferred + read) + " violates maximum of " + _maxSize + " bytes");
|
||||
remaining -= read;
|
||||
if (remaining==0 && _encodingChunked) {
|
||||
if(_proxyIn.read()=='\r' && _proxyIn.read()=='\n') {
|
||||
remaining = (int) readChunkLength();
|
||||
int char1 = _proxyIn.read();
|
||||
if (char1 == '\r') {
|
||||
int char2 = _proxyIn.read();
|
||||
if (char2 == '\n') {
|
||||
remaining = (int) readChunkLength();
|
||||
} else {
|
||||
_out.write(char1);
|
||||
_out.write(char2);
|
||||
_bytesTransferred += 2;
|
||||
remaining -= 2;
|
||||
read += 2;
|
||||
}
|
||||
} else {
|
||||
_out.write(char1);
|
||||
_bytesTransferred++;
|
||||
remaining--;
|
||||
read++;
|
||||
}
|
||||
}
|
||||
if (read > 0)
|
||||
timeout.resetTimer();
|
||||
if (_bytesRemaining >= read) // else chunked?
|
||||
_bytesRemaining -= read;
|
||||
if (read > 0) {
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).bytesTransferred(
|
||||
_alreadyTransferred,
|
||||
@@ -412,16 +568,33 @@ public class EepGet {
|
||||
_bytesTransferred,
|
||||
_encodingChunked?-1:_bytesRemaining,
|
||||
_url);
|
||||
// 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.
|
||||
// Do this after calling the listeners to keep the total correct
|
||||
_alreadyTransferred += read;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_out != null)
|
||||
_out.close();
|
||||
_out = null;
|
||||
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP data");
|
||||
|
||||
timeout.cancel();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Done transferring " + _bytesTransferred);
|
||||
_log.debug("Done transferring " + _bytesTransferred + " (ok? " + !_transferFailed + ")");
|
||||
|
||||
if ( (_bytesRemaining == -1) || (remaining == 0) ){
|
||||
|
||||
if (_transferFailed) {
|
||||
// 404, etc - transferFailed is called after all attempts fail, by fetch() above
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, new Exception("Attempt failed"));
|
||||
} else if ((_minSize > 0) && (_alreadyTransferred < _minSize)) {
|
||||
throw new IOException("Bytes transferred " + _alreadyTransferred + " violates minimum of " + _minSize + " bytes");
|
||||
} else if ( (_bytesRemaining == -1) || (remaining == 0) ) {
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).transferComplete(
|
||||
_alreadyTransferred,
|
||||
@@ -442,32 +615,57 @@ public class EepGet {
|
||||
boolean read = DataHelper.readLine(_proxyIn, buf);
|
||||
if (!read) throw new IOException("Unable to read the first line");
|
||||
int responseCode = handleStatus(buf.toString());
|
||||
|
||||
boolean redirect = false;
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("rc: " + responseCode + " for " + _actualURL);
|
||||
boolean rcOk = false;
|
||||
switch (responseCode) {
|
||||
case 200: // full
|
||||
if (_outputStream != null) _out = _outputStream;
|
||||
else _out = new FileOutputStream(_outputFile, false);
|
||||
if (_outputStream != null)
|
||||
_out = _outputStream;
|
||||
else
|
||||
_out = new FileOutputStream(_outputFile, false);
|
||||
_alreadyTransferred = 0;
|
||||
rcOk = true;
|
||||
break;
|
||||
case 206: // partial
|
||||
if (_outputStream != null) _out = _outputStream;
|
||||
else _out = new FileOutputStream(_outputFile, true);
|
||||
if (_outputStream != null)
|
||||
_out = _outputStream;
|
||||
else
|
||||
_out = new FileOutputStream(_outputFile, true);
|
||||
rcOk = true;
|
||||
break;
|
||||
case 301: // various redirections
|
||||
case 302:
|
||||
case 303:
|
||||
case 307:
|
||||
_alreadyTransferred = 0;
|
||||
rcOk = true;
|
||||
redirect = true;
|
||||
break;
|
||||
case 304: // not modified
|
||||
_bytesRemaining = 0;
|
||||
_keepFetching = false;
|
||||
_notModified = true;
|
||||
return;
|
||||
return;
|
||||
case 404: // not found
|
||||
_keepFetching = false;
|
||||
_transferFailed = true;
|
||||
return;
|
||||
case 416: // completed (or range out of reach)
|
||||
_bytesRemaining = 0;
|
||||
_keepFetching = false;
|
||||
return;
|
||||
default:
|
||||
rcOk = false;
|
||||
_transferFailed = true;
|
||||
}
|
||||
|
||||
// clear out the arguments, as we use the same variables for return values
|
||||
_etag = null;
|
||||
_lastModified = null;
|
||||
|
||||
buf.setLength(0);
|
||||
byte lookahead[] = new byte[3];
|
||||
while (true) {
|
||||
@@ -500,6 +698,7 @@ public class EepGet {
|
||||
if (_encodingChunked) {
|
||||
_bytesRemaining = readChunkLength();
|
||||
}
|
||||
if (!redirect) _redirectLocation = null;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -589,11 +788,15 @@ public class EepGet {
|
||||
}
|
||||
} else if (key.equalsIgnoreCase("ETag")) {
|
||||
_etag = val.trim();
|
||||
} else if (key.equalsIgnoreCase("Last-Modified")) {
|
||||
_lastModified = val.trim();
|
||||
} else if (key.equalsIgnoreCase("Transfer-encoding")) {
|
||||
if (val.indexOf("chunked") != -1)
|
||||
_encodingChunked = true;
|
||||
} else if (key.equalsIgnoreCase("Content-Type")) {
|
||||
_contentType=val;
|
||||
} else if (key.equalsIgnoreCase("Location")) {
|
||||
_redirectLocation=val.trim();
|
||||
} else {
|
||||
// ignore the rest
|
||||
}
|
||||
@@ -616,13 +819,13 @@ public class EepGet {
|
||||
private static final byte NL = '\n';
|
||||
private boolean isNL(byte b) { return (b == NL); }
|
||||
|
||||
private void sendRequest() throws IOException {
|
||||
private void sendRequest(SocketTimeout timeout) throws IOException {
|
||||
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 {
|
||||
} else {
|
||||
File outFile = new File(_outputFile);
|
||||
if (outFile.exists())
|
||||
_alreadyTransferred = outFile.length();
|
||||
@@ -630,24 +833,34 @@ public class EepGet {
|
||||
|
||||
String req = getRequest();
|
||||
|
||||
if (_proxyIn != null) try { _proxyIn.close(); } catch (IOException ioe) {}
|
||||
if (_proxyOut != null) try { _proxyOut.close(); } catch (IOException ioe) {}
|
||||
if (_proxy != null) try { _proxy.close(); } catch (IOException ioe) {}
|
||||
|
||||
if (_shouldProxy) {
|
||||
_proxy = new Socket(_proxyHost, _proxyPort);
|
||||
} else {
|
||||
try {
|
||||
URL url = new URL(_url);
|
||||
String host = url.getHost();
|
||||
int port = url.getPort();
|
||||
if (port == -1)
|
||||
port = 80;
|
||||
_proxy = new Socket(host, port);
|
||||
URL url = new URL(_actualURL);
|
||||
if ("http".equals(url.getProtocol())) {
|
||||
String host = url.getHost();
|
||||
int port = url.getPort();
|
||||
if (port == -1)
|
||||
port = 80;
|
||||
_proxy = new Socket(host, port);
|
||||
} else {
|
||||
throw new IOException("URL is not supported:" + _actualURL);
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
throw new IOException("Request URL is invalid");
|
||||
}
|
||||
}
|
||||
_proxyIn = _proxy.getInputStream();
|
||||
_proxyOut = _proxy.getOutputStream();
|
||||
|
||||
_proxyOut.write(req.toString().getBytes());
|
||||
|
||||
timeout.setSocket(_proxy);
|
||||
|
||||
_proxyOut.write(DataHelper.getUTF8(req.toString()));
|
||||
_proxyOut.flush();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -659,12 +872,24 @@ public class EepGet {
|
||||
boolean post = false;
|
||||
if ( (_postData != null) && (_postData.length() > 0) )
|
||||
post = true;
|
||||
URL url = new URL(_actualURL);
|
||||
String proto = url.getProtocol();
|
||||
String host = url.getHost();
|
||||
int port = url.getPort();
|
||||
String path = url.getPath();
|
||||
String query = url.getQuery();
|
||||
if (query != null)
|
||||
path = path + "?" + query;
|
||||
if (!path.startsWith("/"))
|
||||
path = "/" + path;
|
||||
if ( (port == 80) || (port == 443) || (port <= 0) ) path = proto + "://" + host + path;
|
||||
else path = proto + "://" + host + ":" + port + path;
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + path);
|
||||
if (post) {
|
||||
buf.append("POST ").append(_url).append(" HTTP/1.1\r\n");
|
||||
buf.append("POST ").append(_actualURL).append(" HTTP/1.1\r\n");
|
||||
} else {
|
||||
buf.append("GET ").append(_url).append(" HTTP/1.1\r\n");
|
||||
buf.append("GET ").append(_actualURL).append(" HTTP/1.1\r\n");
|
||||
}
|
||||
URL url = new URL(_url);
|
||||
buf.append("Host: ").append(url.getHost()).append("\r\n");
|
||||
if (_alreadyTransferred > 0) {
|
||||
buf.append("Range: bytes=");
|
||||
@@ -677,11 +902,16 @@ public class EepGet {
|
||||
buf.append("Cache-control: no-cache\r\n");
|
||||
buf.append("Pragma: no-cache\r\n");
|
||||
}
|
||||
if (_etag != null) {
|
||||
if ((_etag != null) && (_alreadyTransferred <= 0)) {
|
||||
buf.append("If-None-Match: ");
|
||||
buf.append(_etag);
|
||||
buf.append("\r\n");
|
||||
}
|
||||
if ((_lastModified != null) && (_alreadyTransferred <= 0)) {
|
||||
buf.append("If-Modified-Since: ");
|
||||
buf.append(_lastModified);
|
||||
buf.append("\r\n");
|
||||
}
|
||||
if (post)
|
||||
buf.append("Content-length: ").append(_postData.length()).append("\r\n");
|
||||
buf.append("Connection: close\r\n\r\n");
|
||||
@@ -696,6 +926,10 @@ public class EepGet {
|
||||
return _etag;
|
||||
}
|
||||
|
||||
public String getLastModified() {
|
||||
return _lastModified;
|
||||
}
|
||||
|
||||
public boolean getNotModified() {
|
||||
return _notModified;
|
||||
}
|
||||
|
@@ -36,7 +36,8 @@ public class EepGetScheduler implements EepGet.StatusListener {
|
||||
public void fetch(boolean shouldBlock) {
|
||||
//Checking for a valid index is done in fetchNext, so we don't have to worry about it.
|
||||
if (shouldBlock) {
|
||||
fetchNext();
|
||||
while (_curURL < _urls.size())
|
||||
fetchNext();
|
||||
} else {
|
||||
fetch();
|
||||
}
|
||||
@@ -77,6 +78,7 @@ public class EepGetScheduler implements EepGet.StatusListener {
|
||||
_listener.transferFailed(url, bytesTransferred, bytesRemaining, currentAttempt);
|
||||
fetchNext();
|
||||
}
|
||||
public void attempting(String url) { _listener.attempting(url); }
|
||||
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
}
|
||||
|
@@ -207,11 +207,11 @@ public class SimpleTimer {
|
||||
_occurredEventCount += eventsToFire.size();
|
||||
} else {
|
||||
_occurredTime = now;
|
||||
if (_occurredEventCount > 1000) {
|
||||
if (_occurredEventCount > 2500) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("Too many simpleTimerJobs (").append(_occurredEventCount);
|
||||
buf.append(") in a second!");
|
||||
_log.log(Log.CRIT, buf.toString());
|
||||
_log.log(Log.WARN, buf.toString());
|
||||
}
|
||||
_occurredEventCount = 0;
|
||||
}
|
||||
|
71
core/java/src/net/i2p/util/SocketTimeout.java
Normal file
71
core/java/src/net/i2p/util/SocketTimeout.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class SocketTimeout implements SimpleTimer.TimedEvent {
|
||||
private Socket _targetSocket;
|
||||
private long _startTime;
|
||||
private long _inactivityDelay;
|
||||
private long _lastActivity;
|
||||
private long _totalTimeoutTime;
|
||||
private boolean _cancelled;
|
||||
private Runnable _command;
|
||||
public SocketTimeout(long delay) { this(null, delay); }
|
||||
public SocketTimeout(Socket socket, long delay) {
|
||||
_inactivityDelay = delay;
|
||||
_targetSocket = socket;
|
||||
_cancelled = false;
|
||||
_lastActivity = _startTime = System.currentTimeMillis();
|
||||
_totalTimeoutTime = -1;
|
||||
SimpleTimer.getInstance().addEvent(SocketTimeout.this, delay);
|
||||
}
|
||||
public void timeReached() {
|
||||
if (_cancelled) return;
|
||||
|
||||
if ( ( (_totalTimeoutTime > 0) && (_totalTimeoutTime <= System.currentTimeMillis()) ) ||
|
||||
(_inactivityDelay + _lastActivity <= System.currentTimeMillis()) ) {
|
||||
if (_targetSocket != null) {
|
||||
try {
|
||||
if (!_targetSocket.isClosed())
|
||||
_targetSocket.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
if (_command != null) _command.run();
|
||||
} else {
|
||||
SimpleTimer.getInstance().addEvent(SocketTimeout.this, _inactivityDelay);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
_cancelled = true;
|
||||
SimpleTimer.getInstance().removeEvent(SocketTimeout.this);
|
||||
}
|
||||
public void setSocket(Socket s) { _targetSocket = s; }
|
||||
public void resetTimer() { _lastActivity = System.currentTimeMillis(); }
|
||||
public void setInactivityTimeout(long timeout) { _inactivityDelay = timeout; }
|
||||
public void setTotalTimeoutPeriod(long timeoutPeriod) {
|
||||
if (timeoutPeriod > 0)
|
||||
_totalTimeoutTime = _startTime + timeoutPeriod;
|
||||
else
|
||||
_totalTimeoutTime = -1;
|
||||
}
|
||||
public void setTimeoutCommand(Runnable job) { _command = job; }
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS");
|
||||
private static String ts(long when) { synchronized (_fmt) { return _fmt.format(new Date(when)); } }
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("started on ");
|
||||
buf.append(ts(_startTime));
|
||||
buf.append("idle for ");
|
||||
buf.append(System.currentTimeMillis() - _lastActivity);
|
||||
buf.append("ms ");
|
||||
if (_totalTimeoutTime > 0)
|
||||
buf.append("total timeout at ").append(ts(_totalTimeoutTime));
|
||||
buf.append("cancelled? ").append(_cancelled);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
472
history.txt
472
history.txt
@@ -1,4 +1,474 @@
|
||||
$Id: history.txt,v 1.583 2007-08-13 14:42:59 zzz Exp $
|
||||
* 2008-04-26 0.6.1.33 released
|
||||
|
||||
2008-04-20 zzz
|
||||
* Outbound message/Reachability:
|
||||
- Fix a bug from -19 causing the persistent lease selection
|
||||
removed in -17 to be back again
|
||||
- Use netDb-listed-unreachable instead of detected-unreachable
|
||||
for exclusion of unreachable peers from selected leases,
|
||||
as there are potential anonymity problems with using
|
||||
detected-unreachable
|
||||
- Tweak logging some more
|
||||
* NetDb stats: Remove a couple more including the inefficient stat_identities
|
||||
|
||||
2008-04-17 zzz
|
||||
* Reachability:
|
||||
- Track unreachable peers persistently
|
||||
(i.e. separately from shitlist, and not cleared when they contact us)
|
||||
- Exclude detected unreachable peers from inbound tunnels
|
||||
- Exclude detected unreachable peers from selected leases
|
||||
- Exclude detected unreachable floodfill peers from lookups
|
||||
- Show unreachable status on profiles.jsp
|
||||
|
||||
2008-04-16 zzz
|
||||
* SSU/Reachability:
|
||||
- Extend shitlist time from 4-8m to 40-60m
|
||||
- Add some shitlist logging
|
||||
- Don't shitlist twice when unreachable on all transports
|
||||
- Exclude netDb-listed unreachable peers from inbound tunnels;
|
||||
this won't help much since there are very few of these now
|
||||
- Remove 10s delay on inbound UDP connections used for the
|
||||
0.6.1.10 transition
|
||||
- Track and display UDP connection direction on peers.jsp
|
||||
- Show shitlist status in-line on profiles.jsp
|
||||
|
||||
2008-04-15 zzz
|
||||
* SSU Reachability/PeerTestManager:
|
||||
- Back out strict peer ordering until we fix SSU
|
||||
- Back out persistent lease selection until we fix SSU
|
||||
- Fix detection of UDP REJECT_UNSOLICITED by recording status on expiration
|
||||
- Increase known Charlie time to 10m; 3m wasn't enough
|
||||
- Don't continue retransmitting peer test if we know Charlie
|
||||
- Don't run multiple peer tests at once
|
||||
- Tighten test frequency range to 6.5-19.5m, was 0-26m
|
||||
|
||||
2008-04-12 zzz
|
||||
* Addressbook: Disallow '.-' and '-.' in host names
|
||||
* NTCP: Don't drop a connection unless both directions are idle;
|
||||
Fix idle time for outbound connections
|
||||
* Outbound message: Make sure cached lease is in current leaseSet
|
||||
* Stats: Put all NetworkDatabase stats in same group
|
||||
* TunnelPool: Stop building tunnels and leaseSets after client shutdown
|
||||
* i2psnark: Add locking to prevent two I2CP connections
|
||||
|
||||
2008-04-07 zzz
|
||||
* i2psnark:
|
||||
- Implement upstream bandwidth limiting
|
||||
- Fix a rare NPE at startup/shutdown
|
||||
- Really increase retries for .torrent fetch
|
||||
* profiles.jsp: Minor cleanup
|
||||
* DataHelper: Only format < 5s as ms
|
||||
* Eepget: Fix percentage output on command line eepget retries
|
||||
* Lower partipating message priority from 400 to 200
|
||||
* NTCP: Add a debug message
|
||||
* Outbound message: Minor cleanup
|
||||
|
||||
2008-03-30 zzz
|
||||
* ExploratoryPeerSelector: Try NonFailing even more
|
||||
* HostsTxtNamingService: Add reverse lookup support
|
||||
* Outbound message: Minor cleanup
|
||||
* i2psnark TrackerClient: Minor cleanup
|
||||
* checklist.txt: Minor edit
|
||||
* hosts.txt: Add perv.i2p, false.i2p, mtn.i2p2.i2p
|
||||
* i2ptunnel.config: Change CVS client to mtn
|
||||
* netdb.jsp: Show leaseSet destinations using reverse lookup
|
||||
* profiles.jsp: First cut at showing floodfill data
|
||||
|
||||
2008-03-27 zzz
|
||||
* Send messages for the same destination to the same inbound
|
||||
lease to reduce out-of-order delivery.
|
||||
* ExploratoryPeerSelector: Back out the floodfill peer exclusion
|
||||
for now, as it prevents speed rating of those peers
|
||||
|
||||
2008-03-26 zzz
|
||||
* ReseedHandler: Support multiple urls,
|
||||
add netdb.i2p2.de as a 2nd default
|
||||
|
||||
2008-03-25 zzz
|
||||
* i2psnark:
|
||||
- Add support for secondary open trackers
|
||||
- Refactor and simplify the TrackerClient code
|
||||
- Add welterde's tracker to the default list
|
||||
- Don't have eepget retry announces
|
||||
- Slow down tracker contacts if they've failed for a while
|
||||
- Add some debug support showing connections (?p=2)
|
||||
* hosts.txt: Add nickyb.i2p, tracker.welterde.i2p
|
||||
|
||||
2008-03-22 zzz
|
||||
* NewsFetcher: Fix bug causing fetch every 10m
|
||||
|
||||
2008-03-22 zzz
|
||||
* Tunnel Testing:
|
||||
- Fix counting so it really takes 4 consecutive failures
|
||||
rather than 4 total to remove a tunnel
|
||||
- Credit or blame goes to the exploratory tunnel as well
|
||||
as the tunnel being tested
|
||||
- Adjust tunnel test timeout based on tunnel length
|
||||
* ExploratoryPeerSelector: Tweak logging
|
||||
* ProfileOrganizer: Adjust integration calculation again
|
||||
* build.xml: Add to help
|
||||
* checklist.txt: Tweak
|
||||
* readme.html: Fix forum links
|
||||
* netDb: Remove tunnel.testFailedTime
|
||||
|
||||
2008-03-19 zzz
|
||||
* ExploratoryPeerSelector:
|
||||
- Exclude floodfill peers
|
||||
- Tweak the HighCap vs. NonFailing decision; try NonFailing
|
||||
at least a minimum % of the time
|
||||
* i2psnark: Increase retries for .torrent fetch
|
||||
* IRC Proxy: Prevent mIRC from sending an alternate DCC request
|
||||
containing an IP
|
||||
* readme.html: Reorder some items
|
||||
* Stats: Add some more required stats
|
||||
* Streaming lib: Fix slow start to be exponential growth,
|
||||
fix congestion avoidance to be linear growth.
|
||||
Should speed up local connections a lot, and remote
|
||||
connections a little.
|
||||
|
||||
2008-03-14 zzz
|
||||
* Floodfill Search:
|
||||
- Prefer heard-from, unfailing, unshitlisted floodfill peers
|
||||
|
||||
2008-03-14 zzz
|
||||
* ProfileOrganizer:
|
||||
- Use more recent stats to calculate integration
|
||||
- Show that fast peers are also high-capacity on profiles.jsp
|
||||
* readme.html: Update Syndie link
|
||||
* TunnelPool: Update comments
|
||||
* netDb: Report 1-2h uptime as 90m to further frustrate tracking,
|
||||
get rid of the 60s tunnel stats
|
||||
(effective as of .33 to provide cover)
|
||||
|
||||
2008-03-13 zzz
|
||||
* Floodfill Search:
|
||||
- Fix a bug that caused a single FloodfillOnlySearchJob
|
||||
instance to be run multiple times, with unpredictable
|
||||
results
|
||||
- Select ff peers randomly to improve reliability
|
||||
- Add some bulletproofing
|
||||
|
||||
2008-03-11 zzz
|
||||
* ProfileOrganizer:
|
||||
- Don't require a peer to be high-capacity to be
|
||||
well-integrated (not used for anything right now,
|
||||
but want to get it right for possible floodfill verification)
|
||||
- Don't fall back to median for high-capacity threshold
|
||||
if the mean is higher than the median, this prevents
|
||||
frequent large high-capacity counts
|
||||
- Fix high-capacity selector that picked one too many
|
||||
* Console: put well-integrated count back in the summary
|
||||
|
||||
2008-03-10 zzz
|
||||
* EepGet: Fix byte count for bytesTransferred status listeners
|
||||
(fixes command line status)
|
||||
* UpdateHandler:
|
||||
- Fix byte count display
|
||||
- Display final status on router console
|
||||
- Don't allow multiple update jobs to queue up
|
||||
- Increase max retries
|
||||
- Code cleanup
|
||||
- Don't show 'check for update' button when update in progress
|
||||
- Enhance error messages
|
||||
* NetDb: Comment out published netDb stats disabled for .32
|
||||
|
||||
2008-03-08 zzz
|
||||
* TunnelPeerSelectors: Implement strict ordering of peers,
|
||||
based on XOR distance from a random hash
|
||||
separately generated for each tunnel pool
|
||||
|
||||
2008-03-07 zzz
|
||||
* Naming: Optimize lookups for a destkey
|
||||
* ProfileOrganizer, TunnelPoolSettings, ClientPeerSelector:
|
||||
- Prevent peers with matching IPs from joining same tunnel.
|
||||
Match 0-4 bytes of IP (0=off, 1=most restrictive, 4=least).
|
||||
Default is 2 (disallow routers in same /16).
|
||||
Set with router.defaultPool.IPRestriction=x
|
||||
- Comment out unused RebuildPeriod pool setting
|
||||
- Add random key to pool in preparation for XOR peer ordering
|
||||
* SusiMail: Add 'Create Account' link
|
||||
* TunnelDispatcher: Change a common wtf error to a warn
|
||||
|
||||
2008-03-05 zzz
|
||||
* Naming: Make HostsTxt the sole default NamingService
|
||||
(was Meta = PetName + HostsTxt)
|
||||
* Naming: Add two new experimental NamingServices, EepGet and Exec,
|
||||
not enabled by default -
|
||||
see source comments in core/java/src/net/i2p/client/naming
|
||||
for configuration instructions
|
||||
* i2psnark: Don't do a naming lookup for Base64 destkeys
|
||||
* i2psnark: Add a StartAll button
|
||||
* Stats: Add code to disable most stats to save memory.
|
||||
Set on configstats.jsp or set stat.full=false to disable the stats.
|
||||
(true by default for now)
|
||||
|
||||
2008-03-09 Complication
|
||||
* Give the Jetty build file ability to ask permission
|
||||
before downloading the Jetty archive from the web,
|
||||
and to verify its SHA1 + MD5 hashes. Adjust the main build file
|
||||
in accordance with this change.
|
||||
* Improve the release checklist.
|
||||
|
||||
* 2008-03-09 0.6.1.32 released
|
||||
|
||||
2008-03-07 zzz
|
||||
* Update news and version numbers
|
||||
|
||||
2008-03-01 zzz
|
||||
* Fix netdb.knownLeaseSets count reported by floodfill routers
|
||||
(was broken by -3)
|
||||
|
||||
2008-02-27 zzz
|
||||
* i2ptunnel: Add 3-hop option to edit.jsp to match configtunnels.jsp
|
||||
* i2psnark: Remove orion and gaytorrents from default tracker list
|
||||
* Remove orion from jump list and from eepsite_index.html
|
||||
* Jbigi: Change jbigi version to 4.2.2 in build scripts - tested by amiga
|
||||
* Capitalize OutboundMessageDistributor job name
|
||||
* TunnelPool: Add a warning if all tunnels are backlogged
|
||||
|
||||
2008-02-26 zzz
|
||||
* Reintroduce NTCP backlog pushback, with switch back to
|
||||
previous tunnel when no longer backlogged
|
||||
* Catch an nio exception in an NTCP logging statement if loglevel is WARN
|
||||
* IRC Proxy: terminate all messages with \r\n (thanks TrivialPursuit!)
|
||||
|
||||
2008-02-21 zzz
|
||||
* Raise inbound default bandwidth to 32KBps
|
||||
* Fix config.jsp that showed 0KBps share bandwidth by default
|
||||
|
||||
2008-02-19 zzz
|
||||
* Addressbook: Disallow '--' in host names except in IDN,
|
||||
add some reserved host names
|
||||
* I2PTunnel: Clarify edit form
|
||||
* NetDb: Remove many stats from netDb, effective as of .32
|
||||
* profiles.jsp: Display capabilities
|
||||
* Tunnels: Enforce max tunnel length of 8, catch an index error
|
||||
http://forum.i2p/viewtopic.php?t=2561
|
||||
|
||||
2008-02-16 zzz
|
||||
* Fix race in TunnelDispatcher which caused
|
||||
participating tunnel count to seesaw -
|
||||
should increase network capacity
|
||||
* Leave participating tunnels in 10s batches for efficiency
|
||||
* Update participating tunnel ratestat when leaving a tunnel too,
|
||||
to generate a smoother graph
|
||||
* Fix tunnel.participatingMessageCount stat to include all
|
||||
participating tunnels, not just outbound endpoints
|
||||
* Simplify Expire Tunnel job name
|
||||
|
||||
2008-02-13 zzz
|
||||
* PersistentDataStore: Write out 300 records every 10 min
|
||||
rather than 1 every 10 sec;
|
||||
Don't store leasesets to disk or read them in
|
||||
* Combine rates for pools with the same length setting
|
||||
in the new tunnel build algorithm
|
||||
* Clarify a log message in the UpdateHandler
|
||||
|
||||
2008-02-13 zzz
|
||||
* Make graphs clickable to get larger graphs
|
||||
* Change SimpleTimer CRIT to a WARN, increase threshold
|
||||
* Checklist update
|
||||
|
||||
2008-02-11 welterde
|
||||
* Fix an NPE in UDP http://forum.i2p/viewtopic.php?t=2545
|
||||
|
||||
2008-02-10 zzz
|
||||
* Add new tunnel build algorithm (preliminary)
|
||||
* Change NTCP backlogged message from error to warning
|
||||
* Checklist updates
|
||||
|
||||
* 2008-02-10 0.6.1.31 released
|
||||
|
||||
2008-02-10 Complication
|
||||
* Update news and version numbers
|
||||
|
||||
2008-02-06 zzz
|
||||
* build.xml: Add some apps to javadoc
|
||||
* checklist.txt: Add some things
|
||||
* news.xml: make links relative
|
||||
* runplain.sh: Add some comments
|
||||
* wrapper.config: Add some comments
|
||||
|
||||
2008-02-05 Complication
|
||||
* Change the dates too (sorry for such forgetfulness!)
|
||||
|
||||
2008-02-04 Complication
|
||||
* Also use the new key for checking, and add it into news.xml
|
||||
|
||||
2008-02-04 Complication
|
||||
* Added my release signing key into TrustedUpdate.java
|
||||
|
||||
2008-01-31 zzz
|
||||
* NewsFetcher: Change fetch failed from error to warning
|
||||
* installer: Fix URL and "email"
|
||||
* checklist.txt: New release checklist
|
||||
|
||||
2008-01-29 zzz
|
||||
* Addressbook: Change default subscription
|
||||
* ConfigUpdateHandler: Change default news URL
|
||||
* initialNews.xml: Update version to .31
|
||||
* news.xml: More updates
|
||||
* hosts.txt: Add i2p-projekt.i2p
|
||||
* readme.html: More URL updates
|
||||
* SusiDNS: Change references to default subscription
|
||||
|
||||
2008-01-28 zzz
|
||||
* news.xml: Updates, still preliminary
|
||||
* ReseedHandler: Change default URL
|
||||
* i2ptunnel.config: Change default outproxies
|
||||
* readme.html: Change *.i2p.net URLs
|
||||
* help.jsp: Change *.i2p.net URLs
|
||||
* eepsite_index.html: Change stats.i2p addressbook subscription URL
|
||||
* hosts.txt: Add krabs.i2p, true.i2p, www.i2p2.i2p
|
||||
|
||||
* 2008-01-28 0.6.1.30-20 converted from CVS to MTN
|
||||
|
||||
2008-01-08 zzz
|
||||
* addressbook: Limit size of subscribed hosts.txt,
|
||||
don't save old etag or last-modified data
|
||||
* EepGet: Add some logging,
|
||||
enforce size limits even when size not in returned header,
|
||||
don't return old etag or last-modified data,
|
||||
don't call transferFailed listener more than once
|
||||
* Sign my update signing key
|
||||
* NewsFetcher: add last-modified support, reduce number of retries
|
||||
* Error pages: add icon and logo,
|
||||
clarify 'destination not found' and 'proxy not found' pages
|
||||
|
||||
2008-01-07 zzz
|
||||
* profiles.jsp formatting cleanup
|
||||
* NTCP: Reduce max idle time from 60m to 20m
|
||||
* NTCP: Fix idle time on connections with zero messages,
|
||||
correctly drop these connections
|
||||
|
||||
2008-01-03 zzz
|
||||
* addressbook: Do basic validation of hostnames and destkeys
|
||||
* susidns: Add support for the private addressbook,
|
||||
update the text and links somewhat
|
||||
|
||||
2008-01-02 zzz
|
||||
* Add stats.i2p to the jump list
|
||||
* Impose 20MB limit on POSTs and catch OOMs in POST
|
||||
* eepsite_index.html: add stats.i2p services
|
||||
* addressbook: log source of new keys; disallow dests > 516 bytes
|
||||
* addressbook: convert hostnames to lower case to prevent duplicates
|
||||
* susidns: generalize references to orion
|
||||
|
||||
2007-12-29 zzz
|
||||
* Tweak IRC inbound PONG filtering to fix xchat/BitchX lagometers
|
||||
* Allow commas in router.trustedUpdateKeys and router.updateURL again
|
||||
* Change default news host from dev.i2p.net to dev.i2p
|
||||
* Change jetty timeout from 30 to 60 sec (thanks sponge!)
|
||||
|
||||
2007-12-28 zzz
|
||||
* Add zzz's update signing key
|
||||
|
||||
2007-12-26 Complication
|
||||
* Improve reseed handler (less repetitive code,
|
||||
avoid reporting errors when less than 10% of fetches fail)
|
||||
|
||||
2007-12-26 Complication
|
||||
* Escape both CR, LF and CR LF line breaks in Router.saveConfig()
|
||||
and unescape them in DataHelper.loadProps() to support
|
||||
saving and loading config properties with line breaks
|
||||
* Change the update URLs textbox into a textarea like keys have,
|
||||
so different URLs go on different lines
|
||||
* Modify TrustedUpdate to provide a method which supplies a key list
|
||||
delimited with CR LF line breaks
|
||||
* Modify DEFAULT_UPDATE_URL to supply a default URL list
|
||||
delimited with CR LF line breaks
|
||||
* Modify selectUpdateURL() to handle URL lists
|
||||
delimited by any kind of line breaks
|
||||
* Start saving trusted update keys
|
||||
* Improve formatting on configupdate.jsp
|
||||
|
||||
2007-12-22 zzz
|
||||
* Add support for multiple update URLs
|
||||
* Change default for update to use i2p proxy,
|
||||
add several URLs as defaults
|
||||
* Enable trusted key form on configupdate.jsp
|
||||
* Clarify the 'destination not found' error page
|
||||
|
||||
2007-12-16 zzz
|
||||
* i2psnark: remove anonymitytracker from default list
|
||||
|
||||
2007-12-10 zzz
|
||||
* Fix NPE in CLI TrustedUpdate keygen
|
||||
|
||||
2007-12-02 Complication
|
||||
* Commit SAM v2 patch from mkvore (thank you!)
|
||||
* Minor reformatting to preserve consistent whitespace
|
||||
in old SAM classes (new classes unaltered)
|
||||
|
||||
2007-12-01 Complication
|
||||
* Separate the checks "does Jetty .zip file need downloading"
|
||||
and "does Jetty .zip file need extracting" in the Jetty buildfile.
|
||||
First download (unless already done), then extract (unless done).
|
||||
|
||||
2007-11-26 zzz
|
||||
* i2psnark: add timeout for receive inactivity
|
||||
|
||||
2007-11-24 zzz
|
||||
* i2psnark: increase streaming lib write timeout to 240 sec and change
|
||||
timeout action from "ping" to "disconect", as the fix in .30 to
|
||||
honor options on outbound connections led to hung outbound connections
|
||||
(bitfield never transmitted, connection never dropped)
|
||||
|
||||
2007-11-06 jrandom
|
||||
* add i2host.i2p to the jump list
|
||||
|
||||
2007-10-11 zzz
|
||||
* IRC Proxy: Fix several possible anonymity holes:
|
||||
- Block CTCP in NOTICE messages
|
||||
- Block CTCP anywhere in PRIVMSG and NOTICE, not just at first character
|
||||
- Check for lower case commands
|
||||
(Thanks sponge!)
|
||||
|
||||
2007-10-07 jrandom
|
||||
* back out the NTCP backlog pushback, as it could be used to mount an
|
||||
active anonymity attack.
|
||||
|
||||
* 2007-10-07 0.6.1.30 released
|
||||
|
||||
2007-10-07 Complication
|
||||
* Fix an issue in EepGet whereby sending of "etag" and "lastModified" headers
|
||||
broke retrying.
|
||||
|
||||
2007-09-27 zzz
|
||||
* Implement pushback of NTCP transport backlog to the outbound tunnel selection code
|
||||
* Clean up the NTCP and UDP tables on peers.jsp to be consistent,
|
||||
fix some of the sorting
|
||||
|
||||
2007-09-22 zzz
|
||||
* Send messages for the same destination out the same outbound
|
||||
tunnel to reduce out-of-order delivery.
|
||||
|
||||
2007-09-19 zzz
|
||||
* i2psnark: Fix broken multifile torrent Delete;
|
||||
cleanup Storage resources in AddTorrent;
|
||||
don't autostart torrent after Create
|
||||
|
||||
2007-09-18 zzz
|
||||
* eepsite_index.html: Add links to trevorreznik address book
|
||||
* streaming lib: Fix SocketManagerFactory to honor options on outbound connections
|
||||
* streaming lib: Fix setDefaultOptions() when called with a ConnectionOptions parameter
|
||||
* i2psnark: Don't make outbound connections to already-connected peers
|
||||
* i2psnark: Debug logging cleanup
|
||||
|
||||
2007-09-14 zzz
|
||||
* eepget: Increase header timeout to 45s
|
||||
* HTTP proxy: Return a better error message for localhost requests
|
||||
* tunnels: Fix PooledTunnelCreatorConfig memory leak
|
||||
|
||||
2007-09-09 zzz
|
||||
* eepget: Add support for Last-Modified and If-Modified-Since
|
||||
* addressbook: Finish incomplete support for Last-Modified
|
||||
|
||||
2007-09-08 zzz
|
||||
* eepget: Copy over SocketTimeout.java file from syndie
|
||||
|
||||
2007-09-07 jrandom
|
||||
* eepget: Merge timeout support from syndie
|
||||
|
||||
* 2007-08-23 0.6.1.29 released
|
||||
|
||||
|
222
hosts.txt
222
hosts.txt
@@ -1,212 +1,3 @@
|
||||
; TC's hosts.txt guaranteed freshness
|
||||
; $Id: hosts.txt,v 1.169 2006-12-16 17:31:07 jrandom Exp $
|
||||
; changelog:
|
||||
; (1.191) added trac.i2p
|
||||
; (1.190) added archive.syndie.i2p
|
||||
; (1.189) added mtn.i2p
|
||||
; (1.188) added downloads.legion.i2p, politguy.i2p, ninja.i2p
|
||||
; (1.187) added hidden.i2p, bk1k.i2p, antipiracyagency.i2p
|
||||
; (1.186) added decadence.i2p, freedomarchives.i2p, closedshop.i2p
|
||||
; (1.185) added TheBreton.i2p adab.i2p awup.i2p china.i2p davidkra.i2p
|
||||
; comwiz.i2p dust.i2p eepsites.i2p jmg.i2p kuroneko.i2p
|
||||
; mywastedlife.i2p site.games.i2p squid2.i2p striker.i2p
|
||||
; tracker.awup.i2p zzz.i2p
|
||||
; (1.184) added sion.i2p, betaguru.i2p jnymo.i2p always.i2p gonzo2000.i2p
|
||||
; flipkick.i2p mindisl0st.i2p torapa.i2p wahoo.i2p badfish.i2p
|
||||
; slack.i2p bobcat.i2p pycache.awup.i2p lp.i2p amazone.i2p
|
||||
; inproxy.tino.i2p kohaar.i2p
|
||||
; (1.183) added ttc.i2p
|
||||
; (1.182) added tracker-fr.i2p
|
||||
; (1.181) added syncline.i2p, cerebrum.i2p, news.underscore.i2p,
|
||||
; onionforum.i2p, frostmirror.i2p, ptm.i2p, gloinsblog.i2p
|
||||
; underscore.i2p, mac7.i2p, wiht.i2p, jazzy.i2p, trwcln.i2p
|
||||
; (1.180) added tino.i2p and fproxy.tino.i2p
|
||||
; (1.179) added glog.i2p
|
||||
; (1.178) added syndie.i2p and syndiemedia.i2p
|
||||
; (1.177) added irc.freshcoffee.i2p
|
||||
; (1.176) added surrender.adab.i2p
|
||||
; (1.175) added terror.i2p
|
||||
; (1.174) added irc.arcturus.i2p
|
||||
; (1.173) added tracker.postman.i2p, hq.postman.i2p
|
||||
; (1.172) added i2p-bt.postman.i2p
|
||||
; (1.171) added luckypunk.i2p
|
||||
; (1.170) added bash.i2p, stats.i2p
|
||||
; (1.169) added archive.i2p, www.fr.i2p, romster.i2p, marshmallow.i2p, openforums.i2p
|
||||
; (1.168) removed duplicate manveru.i2p
|
||||
; (1.167) added bittorrent.i2p
|
||||
; (1.166) added elf.i2p, de-ebooks.i2p, i2pchan.i2p, longhorn.i2p
|
||||
; (1.165) added amobius.i2p
|
||||
; (1.164) added google.i2p
|
||||
; (1.163) added mrplod.i2p
|
||||
; (1.162) added sirup.i2p
|
||||
; (1.161) added connelly.i2p
|
||||
; (1.160) added wspucktracker.i2p
|
||||
; (1.159) added 55cancri.i2p
|
||||
; (1.158) added tracker.fr.i2p
|
||||
; (1.157) added v2mail.i2p, complication.i2p
|
||||
; (1.156) added lazyguy.i2p
|
||||
; (1.155) added confessions.i2p, rsync.thetower.i2p, redzara.i2p, gaytorrents.i2p
|
||||
; (1.154) added arkan.i2p, search.i2p, floureszination.i2p, antipiratbyran.i2p
|
||||
; asylum.i2p, templar.i2p
|
||||
; (1.153) added feedspace.i2p
|
||||
; (1.152) added wiki.fr.i2p
|
||||
; (1.151) added septu.i2p
|
||||
; (1.150) added music.i2p, rotten.i2p, wintermute.i2p, kaji2.i2p, aspnet.i2p,
|
||||
; gaming.i2p, nntp.i2p
|
||||
; (1.149) added cowsay.i2p
|
||||
; (1.148) added irc.postman.i2p
|
||||
; (1.147) added subrosa.i2p
|
||||
; (1.146) added moxonom.i2p
|
||||
; (1.145) added sex0r.i2p flock.i2p cneal.i2p www.nntp.i2p wallsgetbombed.i2p
|
||||
; thedarkside.i2p legion.i2p manveru.i2p books.manveru.i2p bt.i2p
|
||||
; (1.144) added riaa.i2p
|
||||
; (1.143) added mpaa.i2p
|
||||
; (1.142) added pants.i2p
|
||||
; (1.141) added irc.carambar.i2p
|
||||
; (1.140) added general.i2p
|
||||
; (1.139) added smeghead.i2p
|
||||
; (1.138) added nntp.fr.i2p
|
||||
; (1.137) added deadgod.i2p
|
||||
; (1.136) added manveru.i2p
|
||||
; (1.135) added fr.i2p
|
||||
; (1.134) added imhotep.i2p
|
||||
; (1.133) added jrandom.dev.i2p (ed. note: yes, i am me)
|
||||
; (1.132) added ttp.i2p
|
||||
; (1.131) added freenet.eco.i2p, tracker.i2p, photo.i2p
|
||||
; (1.130) added hopekiller.i2p, microsoft.i2p, jhor.i2p, badtoys.i2p
|
||||
; (1.129) added mindspore.i2p
|
||||
; (1.128) added irc.ircbnc.i2p
|
||||
; (1.127) added dvdr-core.i2p
|
||||
; (1.126) added j.i2p
|
||||
; (1.125) added bl.i2p
|
||||
; (1.124) removed jap.eco.i2p and bt1.eco.i2p (obsolete)
|
||||
; (1.123) added chat.i2p
|
||||
; (1.122) added phonebooth.i2p
|
||||
; (1.121) added up.i2p
|
||||
; (1.120) added dm.i2p
|
||||
; (1.119) added piespy.i2p
|
||||
; (1.118) added sciencebooks.i2p
|
||||
; (1.117) added forum.fr.i2p, fedo.i2p, and pastebin.i2p
|
||||
; (1.116) added frosk.i2p
|
||||
; (1.115) added theland.i2p
|
||||
; (1.114) added dox.i2p
|
||||
; (1.113) added amiga.i2p
|
||||
; (1.112) added frooze.i2p
|
||||
; (1.111) aliased gott.i2p as jrandom.i2p (ed. note: no, i am not gott)
|
||||
; (1.110) added sonax.i2p
|
||||
; (1.109) added 1.fcp.freenet.i2p and copied fcp.i2p to 2.fcp.freenet.i2p
|
||||
; (1.108) added asciiwhite.i2p
|
||||
; (1.107) added fcp.i2p
|
||||
; (1.106) added greenflog.i2p
|
||||
; (1.105) added bdl.i2p
|
||||
; (1.104) added bacardi.i2p and guttersnipe.i2p
|
||||
; (1.103) added evil.i2p
|
||||
; (1.102) added bsdm.i2p
|
||||
; (1.101) added eschaton.i2p
|
||||
; (1.100) added blog.curiosity.i2p
|
||||
; (1.99) added slacker.i2p
|
||||
; (1.98) added ses.i2p and pdforge.i2p
|
||||
; (1.97) added orion.i2p and protokol.i2p
|
||||
; (1.96) added blog.polecat.i2p
|
||||
; (1.95) added ciaran.i2p
|
||||
; (1.94) added polecat.i2p
|
||||
; (1.93) added susi.i2p
|
||||
; (1.92) removed duplicate beyond.i2p, added edge.i2p
|
||||
; (1.91) added shiftfox.i2p
|
||||
; (1.90) added underground.i2p
|
||||
; (1.89) renamed newsbytetest.i2p to newsbyte.i2p
|
||||
; (1.88) added newsbytetest.i2p
|
||||
; (1.87) updated curiosity.i2p (via signed email)
|
||||
; (1.86) added blueheron.i2p
|
||||
; (1.85) updated files.i2p (after verifying ident)
|
||||
; (1.84) added utansans.i2p
|
||||
; (1.83) added irc.orz.i2p
|
||||
; (1.82) added nano.i2p
|
||||
; (1.81) added ragnarok.i2p
|
||||
; (1.80) added marcos.i2p
|
||||
; (1.79) updated beyond.i2p's key
|
||||
; (1.78) added b.i2p
|
||||
; (1.77) added tinyurl.i2p
|
||||
; (1.76) added detonate.i2p
|
||||
; (1.75) added identiguy.i2p
|
||||
; (1.74) added jabber-2.i2p
|
||||
; (1.73) added jake.i2p
|
||||
; (1.72) added anonymnet.i2p sasquotch.i2p orz.i2p microbleu.i2p {www,smtp,pop3}.postman.i2p
|
||||
; (1.71) added curiosity.i2p
|
||||
; (1.70) added freeciv.nightblade.i2p
|
||||
; (1.69) added xolotl.i2p
|
||||
; (1.68) added modulus.i2p
|
||||
; (1.67) added eepdot.i2p
|
||||
; (1.66) removed datagram_test.i2p
|
||||
; (1.65) added socks1.tor.i2p
|
||||
; (1.64) added sugadude.i2p
|
||||
; (1.63) added files.i2p
|
||||
; (1.62) added beyond.i2p
|
||||
; (1.61) added gott.i2p
|
||||
; (1.60) added linuxagent.i2p
|
||||
; (1.59) added www.i2p, dev.i2p, and cvs.i2p, removed i2pcvs.i2p
|
||||
; (1.58) updated lucky.i2p (after not checking ID, but, c'mon...)
|
||||
; (1.57) added firerabbit.i2p
|
||||
; (1.56) added datagram_test.i2p
|
||||
; (1.55) updated ardvark.i2p (after checking ID)
|
||||
; (1.54) added files.nickster.i2p
|
||||
; (1.53) added brittanyworld.i2p
|
||||
; (1.52) added stasher.i2p
|
||||
; (1.51) changed quadn.i2p to library.i2p
|
||||
; (1.50) added freshcoffee.i2p
|
||||
; (1.49) added ems.i2p
|
||||
; (1.48) added ooo.i2p
|
||||
; (1.47) added fproxy2.i2p
|
||||
; (1.46) removed hypercubus.i2p
|
||||
; (1.45) added thetower.i2p
|
||||
; (1.44) added fproxy.i2p and mrflibble.i2p
|
||||
; (1.43) added files.hypercubus.i2p
|
||||
; (1.42) added www1.squid.i2p
|
||||
; (1.41) added quadn.i2p
|
||||
; (1.40) added nickster2.i2p and irc.nickster.i2p (pointing at IIP)
|
||||
; (1.39) added jdot.i2p
|
||||
; (1.38) added forum.i2p
|
||||
; (1.36) added ferret.i2p
|
||||
; (1.36) added anonynanny.i2p
|
||||
; (1.35) added hypercubus.i2p
|
||||
; (1.34) added ogg.baffled.i2p
|
||||
; (1.33) added morph.i2p
|
||||
; (1.32) added nickster.i2p
|
||||
; (1.31) added mush.zeit.i2p (i2p's first eepMUSH)
|
||||
; (1.30) added xilog.i2p
|
||||
; (1.29) added lucky.i2p, removed lp.i2p
|
||||
; (1.28) added sungo.i2p
|
||||
; (1.27) added jar.i2p
|
||||
; (1.26) added tor-www-proxy.i2p (WWW through tor by human - won't be up 24/7!)
|
||||
; (1.25) added ugha.i2p
|
||||
; (1.24) added reefer.i2p
|
||||
; (1.23) added nic.i2p
|
||||
; (1.22) added www.janonymous.i2p
|
||||
; (1.21) added bluebeam.i2p
|
||||
; (1.20) added echo.baffled.i2p (which runs mihi's echo server - telnet and get replies)
|
||||
; (1.19) added irc.baffled.i2p (which is hooked up with irc.duck.i2p over i2p)
|
||||
; (1.18) added www.aum.i2p, nntp.baffled.i2p, www.baffled.i2p, and ardvark.i2p
|
||||
; (1.17) added gernika's eepsite
|
||||
; (1.16) added duck's scp and hosting server
|
||||
; (1.15) added eco's beta i2psnark server
|
||||
; (1.14) added duck's pgp keyserver
|
||||
; (1.13) added human's eepsite, the mail servers, and luckypunk's eepsite
|
||||
; (1.12) added fillament's chessd server (FICS based clients or telnet to it)
|
||||
; (1.11) added mp3.tc.i2p and mesh.firerabbit.i2p
|
||||
; (1.10) added aum's mp3 and ogg streams
|
||||
; (1.9) added the FCP and HTTP keys for a private entropy node, as well as nm's eepsite
|
||||
; (1.8) updated nightblade's eepsite (after confirming ident w/ trent on iip)
|
||||
; (1.7) added aum's eepsite
|
||||
; (1.6) added fillament's flog/plog and eco's eepsite
|
||||
; (1.5) added duck's irc
|
||||
; (1.4) added eco's JAP tunnel
|
||||
; (1.3) added duck's eepsite
|
||||
; (1.2) fixed duck's subdomain names
|
||||
; (1.1) added nntp, jabber, squid, and i2pcvs (and imported into i2p's cvs for distribution)
|
||||
; (1.0) added dyad.i2p and nightblade.i2p
|
||||
; (0.5) added bozo.i2p
|
||||
; (0.0) added tc.i2p
|
||||
;
|
||||
tc.i2p=3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJcS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7gfqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teMd5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA
|
||||
dyad.i2p=W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYppK9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HCVilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA
|
||||
nightblade.i2p=nyErwSseXbsojcWtNkDyUul0YULtqr6qyWSzIp639Ygpe8juCdgPMLURVXcmlCvo~QPoHg6zt53KpgpGvB1-Wv2SGvc2Mvs~o8USw3ius8fP1URphqcBbulK8Ci0bgknt0kD0AfxqfMz-p~xk1QEMxq2kZEoB3oyIIFnQlpb2ByS74Lx8iKzXTrwWk19I3Dvu4nIq8CBDDwu3lYoCD2kC-jT5pjgglverGPEGN4o55LYVTtfSg4gAJFZeaE4KjBR5P1z7cca6UDjGMWfR0iCa8P3qpkY2ODYpk~8w2xgBbgDq-8Hzik~uraHc598ccS8QpwB0f0Jw~2PZcTjOPdZ-239U6p3tESXa7FXzRBCujv4Bx6CVFRhCmBHpyFnCD-MugZ~vR6XFSS2XBsCT~duXKq94HH2n1iAWslG4Vu44ut1JVhDPFzp~Dk7wujB0tCo2HXH2icRQxOWe37foU4LZSJ4oMpFDACBzwSfcZdIPsVRxGttKQx4yzgffR1Q~Jl7AAAA
|
||||
@@ -376,7 +167,6 @@ irc.carambar.i2p=xfMseaHQgLA-MjJTKZoe8fL8cfjOhJBe1ii23jfdInJoioDTNRLJE4EnMxdda4Z
|
||||
pants.i2p=Nawyl6EPP30naqz3VwiLiThON4i78Peras6RCtMMUdt62vAND1mQGejJaO--eJfICziDMVhGbrtvAOZzlPBxVhswxENkFFawNf6yDVsdJgJgdtg9i7KUU120IgGS5wABdv5w0sAIn19lu7oZT~Yl-MI6um~Wvg6Dc3SPbHSCgNBMXzuUN1yNGkYdM6xOOkqCEl3H~NujG1gqac8EY5Q9edh0DSMpGXP6vCqVbw6C6uO5InfL5G3BCB4mgq-MooflyN5RL3qELIUnwN76QcOIcHhWbNhbMUzFnwra9g7044GnFGgZZHgkd8iQ25d-en87UHnwLVAxzg7nVj7XTEM-l1CoeQCbPtqZNjn--PMPlLL8b4r0eR6SMV63EhZQzm6Z35C3nhKZOKoeCPPrObi6dgQWk1qnisOUu5isXYA4X~e2xhSrDEXw3UTK71Tpxc6VIw5nBCAD~HLGlOCZGWIKsmUvsgjFBsKNwfl5dhnDCXFWqKaw8ZKo7zpAyXfc4A1EAAAA
|
||||
mpaa.i2p=99SlYfaoMM9xHU8Pl9Pdi77YxuPfULgOoNED86rEH~JxLpsLB8g6stATdoGZye3fTVxnuFIrnPBLR6UBPyFS-FSGr2ZfXcknOdNyk~tes5AxaRvSzuqFsJiOpLvsnOLAN~D0Mu7ZmZJybBRSQhqZiVVczQBM6kgh73EyX6WYwLL3RtWu6zoggVuYZbqPhVpGxun22zI1ZGhTaLZtI8XqgHeeQbSv1dYjAxJxGlWzFb88mVvvOt-X-QjT0G1jNa-wjRutRHja-bIXDRpc1-4cffmbXw2IksSpwZ7BPfLrMKrlvzZxnjjAqiatyPGHR5tkczaD~HCI3p5p8JzIMAgfVpfx6NSHLX5n6Ymm~hQCnT60iwjFAP8AB1LXrLeLaIR~V3ryCs14f9psjleTMCrwPn34h38QWWnxX85cQ5n~P-vvz-wu8uksKvCN2fvHDNEhnIFdy~AYAywVn-UjzLwR1~SHemmxhQoGpwm4YWxnAgrHRHtYX3wzx8aNBMogs5EsAAAA
|
||||
riaa.i2p=cpnfxy9veluR3ZnwYeprHrJt7B359PymL0OEUonqKOTVvemHU9h-WBObN0xgfOajDTWhOskbZ~danOnSJGXmsRI1VrxhjCpJ4ruNcKwILjLv9s7Xa7aWp9MeTNdLJTtTIH9n84HMPd3pG6zHncwI54DUwZTqPkvg4k1u~ZU7fmyT0e5xmog1KBnRoE-ZYSkIAM~H-O-hKtrozkC~FHnMsxq14U6YSwL6e6dQmAXHjcF7u75bYNRbCQJfl1k1XWLVtTimbL3TuNR-6vDX0CyRxt~ma~kKBX4qYLX3SZk7uoX9LX0rFTIAk~1zhGm4yvr~YvXKm6dCJeIgaV1hfQyzqU6iuvgx-Pw9bU5SZiY97JezC0Uj6D5r0~nR1zfD4ULy7slfQsI9NipPtdpHIitcbzXjdwmAfSADNt-dy2MFn-6WqxHG9YUaN4cVUp-tquEqf3ppQ9ynbDABDhcu3ZJ85NccpTCcNRkCUobj9fUWls0tw20dxRLkHmXY-U7r64TfAAAA
|
||||
sex0r.i2p=FXBJquP-C0O1YWyd3wa0FiUgFRn3qN4jADGRTlplVD0LPHepWTPZQB~q29Oj30Q439Vd~KBMVTBp64OI04arwH~xbWPPpKRHhWtqtNfYbSk8UQ2JO~eoKuUlkCvF2H7sqLjZuRbzXz9M4hmUbTEnYzbi6udR56OoI4HVe86ixD9of6PuXGli2OnEKCjXgqX6tp9O0gLrEjeqepvyHHwDhyTYmmSaAXaZsjNgRHtKxnSimnYHij5zXcwiGcSmwZpG3~%20CJiiETf59tA32Mcf5TcRztPRHZNfYfTWN~1DdlU1Nv5x3RJptecJFgkWRIuRXd7DDNCxyibIx9kGBExs11wJl1XOWUtVh5PYVcYV5KSy1~Zz-B5Hovb8AFBjam0r2P0zoKB0-7mDhjhHloeOOyV2txVoZQbgpGNXPlFmrsxtpbDaCB0FBqGw2tPLksgqKJpDmNxE3usNMMy8gv2NtZ92fuHcwr95YwwgoDrePB6-AqywWjYlffyQvEdw0zqLs8AAAA
|
||||
flock.i2p=W0fudCJgidi6SxrdX0YrV7k1~5fKiQsopQdSNa-2D-P7wmJE3nipFnlGY9QEiIRMOBf3K48Q406Glf2zuQLjtrmO8li8SGu9iHOAai--aidcRjVS6n2L70iYnYMK5godipzbAROt-pyHroYq1JnDptqPZGHBovDiwJcPWUIY7Qizl9AWkj3FSXvXCRnb8aeLOVFUiKKPKw~mQ7BPUFWKjmVUuJFON2kxzEBm4p~V4EUR4KGijb3-8JYnMVC4PRk5KNGGxaQ6vO2mnW2Ix0I4JRhG-KL59Tbn6reQBSCL~jiZg9~v7NJHMNZJI8Yqv-76Z1sC1Y0b0fm58J-yO-gQxBlA9CPRpA9uVsckD6wMww1B0ssYjV8oMRtljEpWvJAH3WCTZuT9~i1rbj2dG46hWvMVI9-vQviEDTGjeMagjUWxNkjxU-2LgHUCrfUKfVwqfzUFV1oDVi3MgvWasIK6zUY4LWFz0e4F8QNllJgSdMoZ6PaLZGbi4s8zaoktITA4AAAA
|
||||
cneal.i2p=rOcHhSaRh8VHx-oViRwBBZM49AM3OykwAyBBMkjSlUluFtUFvVbeQDpmMk7CjqwWYFil-wrGOsQBNZw7tLz1cUlvGvAcs-Ji3W9djNPwlYxiY8OwghAFaWoiIWT3cbDuPnugNp9S5sIIvhCUwtALNDjgxSgR3wFvM3FE-Ye9dZpSophLZbUUIZtaholSjZW5yCC8rGftNr3I06Ax1B52jRm0c-niq6AWLb0wYSc3fUcZsIAeWWFfXNGcHL2X8qcslu~hfklQfL36mWgDySd3sjblt7Xg4DbvYkj5ZejnVJIGqY1ZvbOrZkO8kMEUIyqW8Tk5x8aawlfMDj2Cy2RUa1rOKhJHsTfTMB74SHnsGrYk9Cf~G-~6erIns3S085KK-oS1U9MWP9zOVtTzdtlWGjKktWu49e-xzoNbsH9flDZ6d385On~V2fl~zNqQRs-91pv9MDE63bhxroUI4NWst4mfV9zHjgk7Izt4pO5jmzh3KAF2DgCb2~BcMC-x3CM0AAAA
|
||||
www.nntp.i2p=H63RoPaxWD5GTW0HoceyM0vihVal3vpfPyBbC~9yI0~i0WrCs9twJa6oP7RlhT~AIfFKiWaaZLxsKOODuvSwmuM0K4mFSAVYeCWzYeNnbLFrNn85u7cO~w03Rp5UyrxAFMNVE2Hxrgjw9ZPQGRZ8eE6GGEyx8etzkkXoknS4uDhN-qhfTEuYPiVh0Lel4H~VkdiCwepK0tBbxKeKQYtokoFnosrlGo49krkoXD2hLfxPSc-dFHqaQgQqV3XLzKAsb0NUxNMHA18Vr-WBOcB-OubqONpbWAejcB-X6rcZ9rc1b4mAtU~YeV64WESGf9GLadAKb1Z6bfy2qA~-twMMzQzNHmU5b3F0hcA2LD7kZSljZynoss6M2oWAsifewsQ8lKkgXhoyOHjU4sWRUZSxsObcLuI~HM2eWEOkIsBH3MSInC7BSRKKg7GUK3zj4M7f8muHiozOTWCvw5vevV9ay274N~JRrZVKb83oqC3hGoh8OlInMq5RgyyEmuuqcT-RAAAA
|
||||
@@ -504,4 +294,14 @@ ninja.i2p=XhyN8MgL6DwWE98g2DJlDLHy~02g58IF14LTb472cmSLRj~cHv7wyi1mxy21vtf12oPWRq
|
||||
mtn.i2p=RqXC4xbFK6t3g2wk9SO4RjY7mj1c0DmtMra5c1Md8t-DcNPSjQFmqT97pcZ5IR1JDKqyCO7RI~aATTTMPQexoEeqK9-6Poeh2RA1C81FzcA9sHvjLeg3eB1Cju-sE-IDeFntEvCC4w7wWnpmLzCfdXK7OjSK1wYc6OkqPOLVDEy-N-4UUPlZFWWUghpjBGXGayXz6JRKtoMIwhFQaiKdRvAs32ozM9RM0NWzrCaRLZBIQ6Gg1Ys1wF0-oBJgC4T4CN6SxJNaz9Dfw4GNtPyD6lq3S1osY1ccflm3itvUt3JC1J9ypoXzylBE5MuS-LTgbgbMdMFty07AoWB~EY8TwW8EQQO07GSzB7hm53u0iCEH44GexhKHtQP-hYbIr3mklo89BvfWIRGMTwUkAzYojzC-vOyIh16LWrQQhGbLvByKQSdWk9nInm3GEfqRVtSpuqd4m6iHzrBDZ3fvKjbuywot3hDNHitOHOedmBNA8neCzLkod8b0Z4xx~qRIEObxAAAA
|
||||
archive.syndie.i2p=iXX0DadZTJQpPr1to0OmQ4xokHgx1HYd5ec7~zIjQ80W~p4kRCYJmEzibH2Kn59Gi04SAXeA2O9i3bNqfGCQjsbz7UcjPGrW6-UrckXVXW67Moxp7QWY6i-aKuVYM3bqYxUL2mWvcDzJ8D0ecMpvasxhxwXpdFn2J6CGboMxeGV8R3hwwlNYbYoKgHr74qEJaIZpm1FrRWvNHV5cMv363iWnPy72XspQefk79-VOjPsxfummosU7gqlxl5teyiGKNzMs3G6iJyfVHO8IlKtdn~P~ET9p7zWlTPgV8NTyCVB-Wn5S3JMkMGOFZR7wSlxSwGFpTFQKc7mxVTtLZ5nWcV2OhvOIxRZ31RvGJZyVs562RC5aMfyqcM5IHQiZVlmkhzJKIy9VDw8tKayQtRM-xeN5k6Qr7iMmYIRORwuAODkYApoMD9a0eJ6ZYOSgBMOCSvYcwfT8axRY~GabiHm0QC82mo-nDgrUypGKtOPMI9MIqMTsb8Yl-UGWn6twBAIzAAAA
|
||||
trac.i2p=OBnF9NtkEsPij2F-lp3bWDVrJsPQQPdq6adlpq0N4BY1XRjtDBZl~EpDdk7roq49~ptKAQG2cNUeBEKIIrdlZhJio5pMwUl6YinizzkNTFfZipB5OKoB7PBulxkw-N9mKMhS1btd9ajcV8tiP3xiv7VSlgiDwbdKg1fmkvNrVrJnzkN3-ey2kebYnbh7jjU2gPFUl~CwSEkIi6AK9EfqmFR-DUVohyygqAY~fi4EMeTVXGUqftXSNFYUwpRJgFrWRPTurtZnJK5403q67oEk0eWrPIZ8ytJWSBfffAXL3ts~0O1FZeKXUccsAl33j70~lklSolNVLJ40y-6X5ZLWajmX0ONU3j0qI5A~7fgNgsg-vKypPDuzl8ug-D~BmhqdAf0sRYmziDVwTgU~WRB6IzhhXFR6CbwrGXdgOGg2qNT1eOnMwGo3SMMJ7kK88VC5LdYg2dyiyjZATuvT92QdZglrVQIeBqAehcFjOBuycC1ED3AOak8D9Xplj7V6hN-HAAAA
|
||||
|
||||
trevorreznik.i2p=FxoG5dx6WuF8gu0Fc4ItB61hd8dBZ0L6FjkvoA-kQrC0DcY5YUqKBUmrcxzKhKo4nLyg0jRV-RSNUuWsali44dmpHQ6wuFjCGTr5zMk0NoVUpBsBNtHLEQWxROnuQFlQAq6x~eVdU5bAvnNFd-6RXDJ86Br9bf5YG4PHmZPon7ld3t1kAvPaZepITKlIq5iXy3va-pzAMFEIhDtLMzFjGhLWMg9m-8tkx4577WvzUWbSAUdxKkxwjecIzbTDTQsZld~t5MkaMmn5UpNX6Gh3iDUPWHXOjn4I8MIELiSaeRdpHDgua3mo~p8oO0QvWBgn~jQ8yr6nz7vMAdoRtOwPlUqHCCM1BsPVcN9a92rPpTFBk0BXikjJJrkDDIaFjJnKmRAsEUoa-eHaPV~RS0QPrfuzlp0XjBzQcAQjNIw6hO4xqJujSs8SdObMpQAqCR5Sc5NzOvTr5eAzCIz0gmQnKrA1RJVOebKDERM~qQ6rFrdVDkjLEJd6SyjUr-TdIrayAAAA
|
||||
i2host.i2p=FkX89~FOWc2HjTeVerud7hzZCtQNDKqEvMeJiDEnSzneA44hhDEDSbjiDuEWOCPwvgCwrzMg9o3apHXosNMnRVTYlYIJWb1~fgRnzkHIJnz2yrojLcTElTLMgQSzHdV04ock3oPHjw8r2j73hnTiq5u3HhexT0D-IK02S0GUd9cPcP2YnWlNMnGuA-J6s7VHUd5mUhBO3LeOcOusBUOjsbt79bwBZYsnnVV~JRSVzHPd8kYbRMEjDuyaIJHEr2pkwwtrk~BqLeZ5UCbbVob1-733FtOfQXjKTpFPK~IlHDM7ItgXt77U5KZHkZ54WQYJNCE6HlE7LhFB79cqjgvxXTfvyjoqZVJ1lq1yFS8GtLcnurJLkN5BleCEDJEK3D7kCymCpngW9wlKjakEc85ZculU65neqIpqIk6noir6e1vseeUZKxBM3k6AYkLoFYSh98PpENjTHUdaNTl1kQA2Mmi9zobGS0gn0~RWHFord19TC5ReBtOFWkseksHp-5-nAAAA
|
||||
true.i2p=Jeb1Ctlh55wWezbA~sCxYQsreDPS~qFJ6DeNMPl7~Kx0w1Odh8YE3QKrZS7WlNqeoRNJLyPgf7h19Tosb-ATZOPDH7B4pQvI4CdlTv-Uimq4dI71PRRZQr3mCBihW~WtVReDOO3JiDf1Bx225xhTmWp0KYo5AM91EW0TcHi8immHBFB9jcjekPoU~zlVAqy5S07LnS7f7rWtC7kno983Dyi9arWDPmnnzu2QD4mMrH0EkuuoBqwUi1HBUNhTn~lL8KqfSpg9j9q-eqd~eixF3nOlsrxMFuWVV1HOUtyMUTRGEX4i4IDPWmRQeFZ0gmfeBYdad~nG1X7uBVeeEtGSrggnegXoSE4oaIuONNXYORsevZn8UahC~kkNWg1wPQtr57TirhLirkF2qHUuwAqe5G00PIhC0-J8K5Ye0QDd5a1coQT87kBgcqLcbSR1oGIjxv2Ma6970Fv65a2a~YKqZZbuGof5-5-7X48SVhOigmo2c-COyt2rXoQlGQpBWtDsAAAA
|
||||
krabs.i2p=k6qIwzff6s1RiRQQy9O6cliBTfHffKZ2F~pVG8nmCqMxEpPnywynFa9XVS6VBbhxGRAMG~PIb2IaFRYS5GFdM3fnnJ~Cn2AbN-qsqbl6cXExj5Fy9Cd-aPR44XW0NE9qjFPiN~6JUOg0fitF65RmsMrFvHq9LM2zOFxOfnPKVsBJGRpjhp6EPRNrkXvzQTw7x6~kqUJ-VGW0avjrz4EmgT6Wias5z0EPioneKOhG-1NepL8HqEv9ryGt31~kmI1-B0cS8v1riaXH0rZWjJ0VvUFEoJ3sHCir4vsnSf1YQIKMUO~zKlgTVZBsw8P2ILFFihs0g9KMIWVjJqqo0PzCM1O-LW90hirn~Ryh4zOZI-orIiV9Oqu96Fj2bvBYSka11TY7erLOCk64tc5NwxvlJQ3F-lk0ZFGvYuU~l45mi0khFLnDnzhDFtcY6YNLRG8hmv9IR2MrG9TJFfSwXdx11LI-57tkRi9Jw4s8OjLijNNDOJX~rVgwZVVIEQcOhGxkAAAA
|
||||
www.i2p2.i2p=-KR6qyfPWXoN~F3UzzYSMIsaRy4udcRkHu2Dx9syXSzUQXQdi2Af1TV2UMH3PpPuNu-GwrqihwmLSkPFg4fv4yQQY3E10VeQVuI67dn5vlan3NGMsjqxoXTSHHt7C3nX3szXK90JSoO~tRMDl1xyqtKm94-RpIyNcLXofd0H6b02683CQIjb-7JiCpDD0zharm6SU54rhdisIUVXpi1xYgg2pKVpssL~KCp7RAGzpt2rSgz~RHFsecqGBeFwJdiko-6CYW~tcBcigM8ea57LK7JjCFVhOoYTqgk95AG04-hfehnmBtuAFHWklFyFh88x6mS9sbVPvi-am4La0G0jvUJw9a3wQ67jMr6KWQ~w~bFe~FDqoZqVXl8t88qHPIvXelvWw2Y8EMSF5PJhWw~AZfoWOA5VQVYvcmGzZIEKtFGE7bgQf3rFtJ2FAtig9XXBsoLisHbJgeVb29Ew5E7bkwxvEe9NYkIqvrKvUAt1i55we0Nkt6xlEdhBqg6xXOyIAAAA
|
||||
i2p-projekt.i2p=8ZAW~KzGFMUEj0pdchy6GQOOZbuzbqpWtiApEj8LHy2~O~58XKxRrA43cA23a9oDpNZDqWhRWEtehSnX5NoCwJcXWWdO1ksKEUim6cQLP-VpQyuZTIIqwSADwgoe6ikxZG0NGvy5FijgxF4EW9zg39nhUNKRejYNHhOBZKIX38qYyXoB8XCVJybKg89aMMPsCT884F0CLBKbHeYhpYGmhE4YW~aV21c5pebivvxeJPWuTBAOmYxAIgJE3fFU-fucQn9YyGUFa8F3t-0Vco-9qVNSEWfgrdXOdKT6orr3sfssiKo3ybRWdTpxycZ6wB4qHWgTSU5A-gOA3ACTCMZBsASN3W5cz6GRZCspQ0HNu~R~nJ8V06Mmw~iVYOu5lDvipmG6-dJky6XRxCedczxMM1GWFoieQ8Ysfuxq-j8keEtaYmyUQme6TcviCEvQsxyVirr~dTC-F8aZ~y2AlG5IJz5KD02nO6TRkI2fgjHhv9OZ9nskh-I2jxAzFP6Is1kyAAAA
|
||||
nickyb.i2p=9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA
|
||||
tracker.welterde.i2p=BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA
|
||||
perv.i2p=HazSt3kSqVjpMO9Ol9HPjXCfzTLurOPjSeN47UxMLLs4lm5SJJHP-p3vA4sTfxrR3z7Cqq5Nd0t1gog~bV0PCbnKNsTiF~pSPBIFXOPVe5RuX7keDRJ-Mp5-quPIe2FFNEOz7HNkbuz6aHYN74T5Cs2VcMDEvL9Wz~oxV7FPSijD1qs1hi~f3byvSvswRkt4w7A10iJvunq43r1jOi6JwS~lAChP1q7t16sfhtWp4XEaEvfES0bIbnTsRv-aDVy0Kp4zYYPuZstit-S8GHkS7ceDRHSoid1O6V1WgogeDoTRzfxfHqQb5db5xWt4DXmnQbb7xysXub-2S3mbog-WnoawDRM5ZJDItCDuMsg0edIn5RJYkANh0Qox-JMVUZdU8tcx--DX9gONJ4cm4a-MLxY9dme~Zq4hqJJRNRvrRcA11ZuLH-ZN3aTXL70Yod-YyNPcechGrpugKEU38g5sDyj77pX~IrdaTVTFpJE6zlClRatTnl4Enhr4pQ7gWFpcAAAA
|
||||
false.i2p=V5EeX1UrVanCQhE9q-Nj5UFRyQiH6b~lSO7qe8hgxGZkymrpHFZ5j5D9rVOjsogokon1bZF5NPlPdzI~d4Ap7UyqBR~90vhFxsIKednRZLdf46JgjYTZq~ct-Bi3sdpBXdg04L8i4dStE4jkdvl6NF96MfQKdt6mtYFeaXb0XhPx~04NECG5~y~mTYcMjcvrftt5uulLbT6TcGmJ0KV5Xu2UVnkN3zOaQEObIIDZT4wkz9jOqaiJzMHNJqWc4GU4ocIfwxeMkSn9qvA0Q1AXuM~z11~wgHYLVEFoN5k0O4aB8b1r1WtpZTojZ9ADThW89q~AcD981nIYnRp59cmyqBdN7X-71cBrKC7QfnCRJpbwoVrn7kePw1dCu6Bobnd4~a74abxjFeCxVzQxSTbkey6f~wJXE2JPAqfsM1EKXsdqUZQJOP0ngQu16srSpqMSxkqHzlr3US~Vn9EgMcHuDCkdctwo7stwn0UQ34sSF9sLhtmlHIGqatDhfmYEGmSiAAAA
|
||||
mtn.i2p2.i2p=G6VmsrLYbdcxBq585OUcQn7wbwC7J5jfXDWWL6lPBw5iq68VxqxibraiPwwF6NM2aHV8BkqyCKYSL9fUuYWoeUc1zL~2l1DX2x~LfyItGJKDIUGImWQivXF1w7EGYMhjq4UCmPKTsnl4G86oKW8PGaaF8mzjjUKW1R7G7941my~mnbeTrhjlLgaMK-tauVodgTPIYkxfMJaq3zWuirztuUgDcXXIbkpzaA2Iben0VqbjbMJisj4fFh0EvqNkYAG54YBc26~W6SPWyBgZilXvFlcizF90Q5NkIGMMHXTq46qEYHkpQC3CoaH6PMNVDetDPmFc3QXmc68cNcj~VPh4XVsn3qiKhXuRdXggEC3RoTcxqaeassfIG5xhRdnJzGSVhYUE3At~8wI-AuRV~AglV1Q-AZTWT~9VxBzcxfI1PpfzeA-5z5T4542bh1e-RM9tzXEx5ErPCt6M~zJ2~4-tz-aBsZEhBkn0iDi8pazshg6lTl1~hCnueZBxYICqPrlBAAAA
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2007-03-17 20:47:59 $">
|
||||
<i2p.release version="0.6.1.29" date="2007/02/15" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2008-04-26 15:00:00 $">
|
||||
<i2p.release version="0.6.1.33" date="2008/04/26" 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,11 +4,11 @@
|
||||
|
||||
<info>
|
||||
<appname>i2p</appname>
|
||||
<appversion>0.6.1.29</appversion>
|
||||
<appversion>0.6.1.33</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
<author name="I2P" email="http://forum.i2p2.de/"/>
|
||||
</authors>
|
||||
<url>http://www.i2p.net</url>
|
||||
<url>http://www.i2p2.de/</url>
|
||||
</info>
|
||||
|
||||
<guiprefs width="590" height="356" resizable="yes">
|
||||
|
0
installer/lib/launch4j/bin/ld
Normal file → Executable file
0
installer/lib/launch4j/bin/ld
Normal file → Executable file
0
installer/lib/launch4j/bin/ld.exe
Normal file → Executable file
0
installer/lib/launch4j/bin/ld.exe
Normal file → Executable file
0
installer/lib/launch4j/bin/windres
Normal file → Executable file
0
installer/lib/launch4j/bin/windres
Normal file → Executable file
0
installer/lib/launch4j/bin/windres.exe
Normal file → Executable file
0
installer/lib/launch4j/bin/windres.exe
Normal file → Executable file
@@ -6,6 +6,7 @@ Proxy-Connection: close
|
||||
|
||||
<html><head>
|
||||
<title>Destination key conflict</title>
|
||||
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
@@ -31,7 +32,7 @@ div.logo {
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
|
@@ -6,6 +6,7 @@ Proxy-Connection: close
|
||||
|
||||
<html><head>
|
||||
<title>Eepsite not reachable</title>
|
||||
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
@@ -31,13 +32,13 @@ div.logo {
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
The eepsite was not reachable. Perhaps
|
||||
the link you are following is
|
||||
bad. The eepsite could also
|
||||
be temporarily offline. You may want to
|
||||
The eepsite was not reachable.
|
||||
The eepsite is temporarily offline, there is network congestion,
|
||||
or your router is not yet well-integrated with peers.
|
||||
You may want to
|
||||
<a href="javascript: window.location.reload()">retry</a>.
|
||||
<BR><BR>Could not find the following destination:<BR><BR>
|
||||
|
@@ -6,6 +6,7 @@ Proxy-Connection: close
|
||||
|
||||
<html><head>
|
||||
<title>Invalid eepsite destination</title>
|
||||
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
@@ -31,7 +32,7 @@ div.logo {
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
|
@@ -6,6 +6,7 @@ Proxy-Connection: close
|
||||
|
||||
<html><head>
|
||||
<title>Eepsite unknown</title>
|
||||
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
@@ -31,14 +32,13 @@ div.logo {
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
The eepsite was not found in your router's addressbook.
|
||||
Check the link or find a BASE64 address.
|
||||
If you have the BASE64 address, paste it into your userhosts.txt using SusiDNS
|
||||
<a href="http://localhost:7657/susidns/addressbook.jsp?book=master">here</a>.
|
||||
or use a BASE64 address helper.
|
||||
You may be able to find the eepsite's address helper at <a href="http://orion.i2p">orion.i2p</a>.
|
||||
If you have the BASE64 address, paste it into your userhosts.txt using
|
||||
<a href="http://localhost:7657/susidns/addressbook.jsp?book=master">SusiDNS</a>,
|
||||
use a BASE64 address helper, or use a jump service link below.
|
||||
<BR><BR>Could not find the following destination:<BR><BR>
|
||||
|
@@ -6,6 +6,7 @@ Proxy-Connection: close
|
||||
|
||||
<html><head>
|
||||
<title>Outproxy Not Found</title>
|
||||
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
@@ -32,13 +33,14 @@ div.logo {
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
The WWW Outproxy was not found.
|
||||
It could
|
||||
be temporarily offline. You may want to
|
||||
It is offline, there is network congestion,
|
||||
or your router is not yet well-integrated with peers.
|
||||
You may want to
|
||||
<a href="javascript: parent.window.location.reload()">retry</a>
|
||||
as this will randomly reselect an outproxy from the pool you have defined
|
||||
<a href="http://localhost:7657/i2ptunnel/index.jsp">here</a>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#export I2P=~i2p/i2p
|
||||
export I2P=.
|
||||
export I2P=`dirname $0`
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.util.EepGet $*
|
||||
|
@@ -14,16 +14,15 @@
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">configuration page</a>).
|
||||
The instructions below detail how to assign a name like "mysite.i2p" to your key and
|
||||
start up your eepsite.</p>
|
||||
<p>You can also reach your eepsite locally through
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>. If you
|
||||
want to change the port number, edit the file ./eepsite/jetty.xml and
|
||||
update the I2PTunnel configuration accordingly.</p>
|
||||
<p>You can reach your eepsite locally through
|
||||
<a href="http://localhost:7658/">http://localhost:7658/</a>.
|
||||
</p>
|
||||
|
||||
<h2>Step-by-step instructions for starting your new eepsite and announcing it to the I2P community</h2>
|
||||
Your eepsite is stopped by default.
|
||||
After you start it, it will be difficult for other people to find because it
|
||||
doesn't have a name and they don't have your really long Base64 key.
|
||||
You could just tell people that really long key but thankfully i2p has an address book
|
||||
You could just tell people that really long key, but thankfully i2p has an address book
|
||||
and several easy ways to tell people about your eepsite. Here's detailed instructions.
|
||||
<ul>
|
||||
<li>Pick a name for your eepsite (<i>something</i>.i2p). Use all lower-case.
|
||||
@@ -52,35 +51,48 @@
|
||||
<li>Before you tell the world about your new eepsite, you should add some content.
|
||||
Go to i2p/eepsite/docroot and copy this document (index.html) to help.html so you can refer to it later.
|
||||
Now edit index.html and add content, pictures, and whatever you would like to share.
|
||||
<li>Now it's time to add your eepsite to I2P's most popular address book.
|
||||
To do that, you must to tell <a href="http://orion.i2p/">orion.i2p</a>
|
||||
what your eepsite name and key are. Orion has a web interface where you can add a key to the address book.
|
||||
The key entry form is <a href="http://orion.i2p/list/">here</a>.
|
||||
<li>Now it's time to add your eepsite to an I2P address book hosted by a site
|
||||
such as <a href="http://stats.i2p/">stats.i2p</a>.
|
||||
That is, you must enter
|
||||
your eepsite name and key into a web interface on one or more of these sites.
|
||||
Here is <a href="http://stats.i2p/i2p/addkey.html">the key entry form at stats.i2p</a>,
|
||||
and
|
||||
here is <a href="http://trevorreznik.i2p/host-database/">the key entry form at trevorreznik.i2p</a>.
|
||||
Again, your key is the entire "Local destination" key on the
|
||||
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel configuration page</a>.
|
||||
Be sure you get the whole thing, ending with "AAAA".
|
||||
Don't forget to click "add a key".
|
||||
Check to see if it reports the key was added.
|
||||
Since most routers periodically get address book updates from orion, within several hours others will be able to find your
|
||||
Since many routers periodically get address book updates from these sites, within several hours others will be able to find your
|
||||
website by simply typing <i>something</i>.i2p into their browser.
|
||||
<li>If you are in a hurry and can't wait a few hours, you can tell people to use orion's "jump" address helper redirection service.
|
||||
This will work within a few minutes of your entering the key to orion.i2p.
|
||||
Test it yourself first by entering http://orion.i2p/jump/<i>something</i>.i2p into your browser.
|
||||
<li>Speaking of address book updates, this would be a good time to add some more addressbooks
|
||||
to your own subscription list. Go to your <a href="http://localhost:7657/susidns/subscriptions.jsp">subscriptions configuration page</a>
|
||||
and add a couple of these -
|
||||
<a href="http://tino.i2p/hosts.txt">http://tino.i2p/hosts.txt</a>,
|
||||
<a href="http://stats.i2p/cgi-bin/newhosts.txt">http://stats.i2p/cgi-bin/newhosts.txt</a>,
|
||||
<a href="http://trevorreznik.i2p/hosts.txt">http://trevorreznik.i2p/hosts.txt</a> and hit "Save".
|
||||
Now you will get updates too!
|
||||
<li>If you are in a hurry and can't wait a few hours, you can tell people to use a "jump" address helper redirection service.
|
||||
This will work within a few minutes of your entering the key to an address book.
|
||||
Test it yourself first by entering
|
||||
http://stats.i2p/cgi-bin/jump.cgi?a=<i>something</i>.i2p or
|
||||
or http://trevorreznik.i2p/cgi-bin/jump.php?hostname=<i>something</i>.i2p into your browser.
|
||||
Once it's working, then you can tell others to use it.
|
||||
<li>Some people check <a href="http://orion.i2p/list/">orion.i2p/list/</a> for new eepsites, so you may start getting
|
||||
<li>Some people check eepsite lists such as
|
||||
<a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p/status.php</a> for new eepsites, so you may start getting
|
||||
a few visitors. But there are plenty of other ways to tell people. Here are a few ideas:
|
||||
<ul>
|
||||
<li>Post a message on the <a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce forum</a>
|
||||
on <a href="http://forum.i2p/">forum.i2p</a>.
|
||||
<li>Tell people about it on the #i2p or #i2p-chat channels on IRC.
|
||||
<li>Put it in a new post on <a href="syndie.i2p.net">the new Syndie</a>.
|
||||
<li>Put it in a new post on <a href="http://syndie.i2p2.de/">the new Syndie</a>.
|
||||
<li>Put it in <a href="http://ugha.i2p/EepsiteIndex">Ugha's Eepsite Index Wiki</a>
|
||||
</ul>
|
||||
Note that some sites recommend pasting in that really long destination key.
|
||||
You can if you want - but
|
||||
if you have successfully posted your key on the <a href="http://orion.i2p/list/">orion page here</a>,
|
||||
tested it using http://orion.i2p/jump/<i>something</i>.i2p, and waited 24 hours for orion's
|
||||
address book to propagate to others, that shouldn't be necessary.
|
||||
if you have successfully posted your key at an add-key service,
|
||||
tested it using a jump service, and waited 24 hours for the
|
||||
address book update to propagate to others, that shouldn't be necessary.
|
||||
<li>If you have any questions try IRC #i2p or the
|
||||
<a href="http://forum.i2p/viewforum.php?f=10">technical problems section</a> on
|
||||
<a href="http://forum.i2p/">forum.i2p</a>.
|
||||
|
@@ -5,7 +5,7 @@ tunnel.0.type=httpclient
|
||||
tunnel.0.sharedClient=true
|
||||
tunnel.0.interface=127.0.0.1
|
||||
tunnel.0.listenPort=4444
|
||||
tunnel.0.proxyList=squid.i2p
|
||||
tunnel.0.proxyList=true.i2p,krabs.i2p
|
||||
tunnel.0.i2cpHost=127.0.0.1
|
||||
tunnel.0.i2cpPort=7654
|
||||
tunnel.0.option.inbound.nickname=shared clients
|
||||
@@ -29,14 +29,14 @@ tunnel.1.option.i2p.streaming.connectDelay=1000
|
||||
tunnel.1.option.i2p.streaming.maxWindowSize=1
|
||||
tunnel.1.startOnLoad=true
|
||||
|
||||
# I2P's cvs server
|
||||
tunnel.2.name=cvs.i2p
|
||||
tunnel.2.description=I2P CVS pserver
|
||||
# I2P's mtn server
|
||||
tunnel.2.name=mtn.i2p2.i2p
|
||||
tunnel.2.description=I2P Monotone Server
|
||||
tunnel.2.type=client
|
||||
tunnel.2.sharedClient=true
|
||||
tunnel.2.interface=127.0.0.1
|
||||
tunnel.2.listenPort=2401
|
||||
tunnel.2.targetDestination=cvs.i2p
|
||||
tunnel.2.listenPort=8998
|
||||
tunnel.2.targetDestination=mtn.i2p2.i2p
|
||||
tunnel.2.i2cpHost=127.0.0.1
|
||||
tunnel.2.i2cpPort=7654
|
||||
tunnel.2.option.inbound.nickname=shared clients
|
||||
|
@@ -25,7 +25,7 @@
|
||||
</Arg>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MaxThreads">10</Set>
|
||||
<Set name="MaxIdleTimeMs">30000</Set>
|
||||
<Set name="MaxIdleTimeMs">60000</Set>
|
||||
<Set name="LowResourcePersistTimeMs">1000</Set>
|
||||
<Set name="ConfidentialPort">8443</Set>
|
||||
<Set name="IntegralPort">8443</Set>
|
||||
|
@@ -1,3 +1,10 @@
|
||||
#
|
||||
# This runs the router by itself, WITHOUT the wrapper.
|
||||
# This means the router will not restart if it crashes.
|
||||
# Also, you will be using the default memory size, which is
|
||||
# probably not enough for i2p.
|
||||
# You should really use the i2prouter script instead.
|
||||
#
|
||||
export CP=. ; for j in lib/* ; do export CP=$CP:$j ; done;
|
||||
JAVA=java
|
||||
|
||||
|
@@ -1,5 +1,11 @@
|
||||
#********************************************************************
|
||||
# Wrapper Properties
|
||||
#
|
||||
# WARNING - for any changes to take effect, you must completely
|
||||
# stop the router and the wrapper. Clicking 'Restart' on your
|
||||
# router console will NOT reread this file! You must
|
||||
# click "Shutdown", wait 11 minutes, then start i2p.
|
||||
#
|
||||
#********************************************************************
|
||||
# Java Application
|
||||
wrapper.java.command=java
|
||||
@@ -60,6 +66,13 @@ wrapper.java.additional.4=-Dorg.mortbay.xml.XmlParser.NotValidating=true
|
||||
# The JVM's default is 64MB, and I2P can work fine in that, but to handle
|
||||
# lots of I2PSnark activity in the same JVM, increasing the default max heap
|
||||
# size should help. Feel free to reduce this if not using I2PSnark in the jvm
|
||||
# High-bandwidth routers may need to increase to 256 or more.
|
||||
#
|
||||
# WARNING - for any changes to take effect, you must completely
|
||||
# stop the router and the wrapper. Clicking 'Restart' on your
|
||||
# router console will NOT reread this file! You must
|
||||
# click "Shutdown", wait 11 minutes, then start i2p.
|
||||
#
|
||||
wrapper.java.maxmemory=128
|
||||
|
||||
# Application parameters. Add parameters as needed starting from 1
|
||||
|
44
news.xml
44
news.xml
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2007-07-19 13:05:44 $">
|
||||
<i2p.release version="0.6.1.29" date="2007/02/15" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2008-04-26 15:00:00 $">
|
||||
<i2p.release version="0.6.1.33" date="2008/04/26" 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"
|
||||
@@ -9,27 +9,37 @@
|
||||
publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000826.html"
|
||||
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" />
|
||||
<p>
|
||||
•
|
||||
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 />
|
||||
2008-04-26: <b>0.6.1.33 <a href="http://www.i2p2.i2p/release-0.6.1.33.html">Released</a></b>
|
||||
</p><p>
|
||||
The 0.6.1.33 release contains several important bug fixes and performance improvements
|
||||
in SSU reachability detection, floodfill peer selection, tunnel peer selection, tunnel testing,
|
||||
NTCP idle detection, the streaming lib, and news fetching.
|
||||
It also adds secondary tracker support to i2psnark.
|
||||
Please upgrade as soon as you can, as these fixes
|
||||
should improve the reliability of the whole network.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
•
|
||||
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 />
|
||||
2008-04-20: <b><a href="http://trac.i2p2.i2p/">We are now using Trac as bugtracker</a></b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
•
|
||||
2008-02-05: <b>Upgrading from 0.6.1.30 and Earlier Releases</b>
|
||||
</p><p>
|
||||
Full instructions are posted at
|
||||
<a href="http://www.i2p2.i2p/upgrade-0.6.1.30.html">www.i2p2.i2p/upgrade-0.6.1.30.html</a>.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
•
|
||||
2007-04-10:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2007-April/001343.html">status notes</a>
|
||||
and
|
||||
<a href="http://www.i2p/meeting206">meeting log</a>
|
||||
<br />
|
||||
-->
|
||||
</i2p.news>
|
||||
|
28
readme.html
28
readme.html
@@ -3,22 +3,18 @@ grow over the next few minutes and you'll see a "shared clients" local destinati
|
||||
on the left (if not, <a href="#trouble">see below</a>). Once those show up,
|
||||
you can:</p>
|
||||
<ul>
|
||||
<li><b>blog anonymously</b> - check out <a href="http://syndie.i2p/">Syndie</a></li>
|
||||
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the
|
||||
server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
|
||||
IRC servers, but neither you nor they know where the other is.</li>
|
||||
<li><b>browse "eepsites"</b> - on I2P there are anonymously hosted websites -
|
||||
tell your browser to use the <b>HTTP proxy at localhost port 4444</b>, then
|
||||
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://inproxy.tino.i2p/status.php">inproxy.tino.i2p</a> and
|
||||
<a href="http://perv.i2p/stats.cgi">perv.i2p</a>: sites tracking active eepsites</li>
|
||||
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p2.de/">forum.i2p2.de</a></li>
|
||||
<li><a href="http://www.i2p2.i2p/">www.i2p2.i2p</a> and mirror <a href="http://i2p-projekt.i2p">i2p-projekt.i2p</a>:
|
||||
secure and anonymous connections to <a href="http://www.i2p2.de/">www.i2p2.de</a></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>
|
||||
<li><a href="http://fproxy.tino.i2p">fproxy.tino.i2p</a>: Freenet proxy</li>
|
||||
</ul>
|
||||
There are many more eepsites - just follow the links from the ones you see,
|
||||
bookmark your favorites, and visit them often!</li>
|
||||
@@ -32,8 +28,12 @@ you can:</p>
|
||||
<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>.
|
||||
We bundle <a href="http://susi.i2p/">Susi's</a> <a href="/susimail/susimail">susimail</a>,
|
||||
We bundle <a href="/susimail/susimail">susimail</a>,
|
||||
a web based anonymity-oriented pop3/smtp client configured to access postman's mail services.</li>
|
||||
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the
|
||||
server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
|
||||
IRC servers, but neither you nor they know where the other is.</li>
|
||||
<li><b>blog anonymously</b> - check out <a href="http://syndie.i2p2.de/">Syndie</a></li>
|
||||
<li>and lots more</li>
|
||||
</ul>
|
||||
|
||||
@@ -55,11 +55,11 @@ Detailed instructions for starting your eepsite are on
|
||||
<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>),
|
||||
If you cannot see any eepsites at all (even <a href="http://www.i2p2.i2p/">www.i2p2.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
|
||||
<a href="http://www.i2p2.i2p/">I2P website</a>, post up messages to the
|
||||
<a href="http://forum.i2p2.de/">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>
|
||||
|
||||
<p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p>
|
||||
|
@@ -33,8 +33,8 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
|
||||
|
||||
public DatabaseSearchReplyMessage(I2PAppContext context) {
|
||||
super(context);
|
||||
_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "Network Database", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "Network Database", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
|
||||
setSearchKey(null);
|
||||
_peerHashes = new ArrayList(3);
|
||||
setFromHash(null);
|
||||
|
@@ -14,6 +14,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.RouterAddress;
|
||||
|
||||
/**
|
||||
@@ -52,6 +53,8 @@ public abstract class CommSystemFacade implements Service {
|
||||
*/
|
||||
public short getReachabilityStatus() { return STATUS_OK; }
|
||||
public void recheckReachability() {}
|
||||
public boolean isBacklogged(Hash dest) { return false; }
|
||||
public boolean wasUnreachable(Hash dest) { return false; }
|
||||
|
||||
/**
|
||||
* Tell other transports our address changed
|
||||
|
@@ -939,6 +939,10 @@ public class Router {
|
||||
for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = _config.getProperty(key);
|
||||
// Escape line breaks before saving.
|
||||
// Remember: "\" needs escaping both for regex and string.
|
||||
val = val.replaceAll("\\r","\\\\r");
|
||||
val = val.replaceAll("\\n","\\\\n");
|
||||
buf.append(key).append('=').append(val).append('\n');
|
||||
}
|
||||
}
|
||||
|
@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
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 String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
|
||||
public final static String VERSION = "0.6.1.33";
|
||||
public final static long BUILD = 0;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
|
@@ -37,7 +37,7 @@ public class Shitlist {
|
||||
Set transports;
|
||||
}
|
||||
|
||||
public final static long SHITLIST_DURATION_MS = 4*60*1000; // 4 minute shitlist
|
||||
public final static long SHITLIST_DURATION_MS = 40*60*1000; // 40 minute shitlist
|
||||
|
||||
public Shitlist(RouterContext context) {
|
||||
_context = context;
|
||||
@@ -72,6 +72,8 @@ public class Shitlist {
|
||||
if (prof != null)
|
||||
prof.unshitlist();
|
||||
_context.messageHistory().unshitlist(peer);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unshitlisting router (expired) " + peer.toBase64());
|
||||
}
|
||||
|
||||
requeue(30*1000);
|
||||
@@ -152,12 +154,13 @@ public class Shitlist {
|
||||
public void unshitlistRouter(Hash peer, String transport) { unshitlistRouter(peer, true, transport); }
|
||||
private void unshitlistRouter(Hash peer, boolean realUnshitlist, String transport) {
|
||||
if (peer == null) return;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unshitlisting router " + peer.toBase64()
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Calling unshitlistRouter " + peer.toBase64()
|
||||
+ (transport != null ? "/" + transport : ""));
|
||||
boolean fully = false;
|
||||
Entry e;
|
||||
synchronized (_entries) {
|
||||
Entry e = (Entry)_entries.remove(peer);
|
||||
e = (Entry)_entries.remove(peer);
|
||||
if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) {
|
||||
// fully unshitlisted
|
||||
fully = true;
|
||||
@@ -176,6 +179,9 @@ public class Shitlist {
|
||||
prof.unshitlist();
|
||||
}
|
||||
_context.messageHistory().unshitlist(peer);
|
||||
if (_log.shouldLog(Log.INFO) && e != null)
|
||||
_log.info("Unshitlisting router " + peer.toBase64()
|
||||
+ (transport != null ? "/" + transport : ""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +215,8 @@ public class Shitlist {
|
||||
if (prof != null)
|
||||
prof.unshitlist();
|
||||
_context.messageHistory().unshitlist(peer);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unshitlisting router (expired) " + peer.toBase64());
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@@ -103,6 +103,7 @@ public class StatisticsManager implements Service {
|
||||
// stats.setProperty("router.id", RouterVersion.ID);
|
||||
// stats.setProperty("core.id", CoreVersion.ID);
|
||||
|
||||
/***
|
||||
int newlines = 0;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
@@ -122,66 +123,76 @@ public class StatisticsManager implements Service {
|
||||
}
|
||||
if (newlines > 0)
|
||||
stats.setProperty("stat_identities", newlines+"");
|
||||
|
||||
***/
|
||||
|
||||
if (_includePeerRankings) {
|
||||
if (false)
|
||||
stats.putAll(_context.profileManager().summarizePeers(_publishedStats));
|
||||
|
||||
boolean commentMeOutInDot33 = RouterVersion.VERSION.equals("0.6.1.32");
|
||||
includeThroughput(stats);
|
||||
includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
|
||||
includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
|
||||
//includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
|
||||
//includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
|
||||
//includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
|
||||
includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
|
||||
//includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
|
||||
//includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
|
||||
//includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
|
||||
if (commentMeOutInDot33)
|
||||
includeRate("tunnel.testFailedTime", stats, new long[] { 10*60*1000 });
|
||||
|
||||
includeRate("tunnel.buildFailure", stats, new long[] { 60*60*1000 });
|
||||
includeRate("tunnel.buildSuccess", stats, new long[] { 60*60*1000 });
|
||||
|
||||
//includeRate("tunnel.batchDelaySent", stats, new long[] { 10*60*1000, 60*60*1000 });
|
||||
includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
|
||||
//includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
|
||||
includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l });
|
||||
|
||||
//includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
|
||||
//includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
|
||||
//includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
|
||||
|
||||
if (commentMeOutInDot33)
|
||||
includeRate("router.fastPeers", stats, new long[] { 60*60*1000 });
|
||||
|
||||
includeRate("udp.statusOK", stats, new long[] { 20*60*1000 });
|
||||
includeRate("udp.statusDifferent", stats, new long[] { 20*60*1000 });
|
||||
includeRate("udp.statusReject", stats, new long[] { 20*60*1000 });
|
||||
includeRate("udp.statusUnknown", stats, new long[] { 20*60*1000 });
|
||||
includeRate("udp.statusKnownCharlie", stats, new long[] { 1*60*1000, 10*60*1000 });
|
||||
includeRate("udp.addressUpdated", stats, new long[] { 1*60*1000 });
|
||||
includeRate("udp.addressTestInsteadOfUpdate", stats, new long[] { 1*60*1000 });
|
||||
//includeRate("udp.statusOK", stats, new long[] { 20*60*1000 });
|
||||
//includeRate("udp.statusDifferent", stats, new long[] { 20*60*1000 });
|
||||
//includeRate("udp.statusReject", stats, new long[] { 20*60*1000 });
|
||||
//includeRate("udp.statusUnknown", stats, new long[] { 20*60*1000 });
|
||||
//includeRate("udp.statusKnownCharlie", stats, new long[] { 1*60*1000, 10*60*1000 });
|
||||
//includeRate("udp.addressUpdated", stats, new long[] { 1*60*1000 });
|
||||
//includeRate("udp.addressTestInsteadOfUpdate", stats, new long[] { 1*60*1000 });
|
||||
|
||||
includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 });
|
||||
|
||||
//includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
|
||||
//includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
|
||||
if (commentMeOutInDot33) { // get rid of 60s stats
|
||||
includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*1000, 60*60*1000 });
|
||||
} else {
|
||||
includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 });
|
||||
}
|
||||
includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 });
|
||||
includeRate("tunnel.testSuccessTime", stats, new long[] { 10*60*1000l });
|
||||
//includeRate("tunnel.testSuccessTime", stats, new long[] { 10*60*1000l });
|
||||
includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true);
|
||||
includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
|
||||
includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
|
||||
includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 60*1000 });
|
||||
includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
|
||||
//includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
|
||||
//includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
|
||||
//includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 60*1000 });
|
||||
//includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
|
||||
//includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
|
||||
//includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
|
||||
|
||||
// Round smaller uptimes to 1 hour, to frustrate uptime tracking
|
||||
// Round 2nd hour to 90m since peers use 2h minimum to route
|
||||
long publishedUptime = _context.router().getUptime();
|
||||
if (publishedUptime < 60*60*1000) publishedUptime = 60*60*1000;
|
||||
else if (publishedUptime < 2*60*60*1000 && !commentMeOutInDot33) publishedUptime = 90*60*1000;
|
||||
|
||||
stats.setProperty("stat_uptime", DataHelper.formatDuration(publishedUptime));
|
||||
stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
|
||||
//stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
|
||||
|
||||
if (commentMeOutInDot33) { // get rid of 60s stats
|
||||
includeRate("tunnel.buildRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.decryptRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
//includeRate("tunnel.decryptRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.buildClientExpire", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.buildClientReject", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.buildClientSuccess", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
@@ -189,11 +200,23 @@ public class StatisticsManager implements Service {
|
||||
includeRate("tunnel.buildExploratoryReject", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.buildExploratorySuccess", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.rejectTimeout", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("udp.packetDequeueTime", stats, new long[] { 60*1000 });
|
||||
includeRate("udp.packetVerifyTime", stats, new long[] { 60*1000 });
|
||||
//includeRate("udp.packetDequeueTime", stats, new long[] { 60*1000 });
|
||||
//includeRate("udp.packetVerifyTime", stats, new long[] { 60*1000 });
|
||||
|
||||
includeRate("tunnel.rejectOverloaded", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
includeRate("tunnel.acceptLoad", stats, new long[] { 60*1000, 10*60*1000 });
|
||||
} else {
|
||||
includeRate("tunnel.buildRequestTime", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildClientExpire", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildClientReject", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildClientSuccess", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildExploratoryExpire", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildExploratoryReject", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.buildExploratorySuccess", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.rejectTimeout", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.rejectOverloaded", stats, new long[] { 10*60*1000 });
|
||||
includeRate("tunnel.acceptLoad", stats, new long[] { 10*60*1000 });
|
||||
}
|
||||
|
||||
if (FloodfillNetworkDatabaseFacade.isFloodfill(_context.router().getRouterInfo())) {
|
||||
stats.setProperty("netdb.knownRouters", ""+_context.netDb().getKnownRouters());
|
||||
|
@@ -41,6 +41,9 @@ public interface TunnelManagerFacade extends Service {
|
||||
*
|
||||
*/
|
||||
boolean isInUse(Hash peer);
|
||||
|
||||
/** Is a tunnel a valid member of the pool? */
|
||||
public boolean isValidTunnel(Hash client, TunnelInfo tunnel);
|
||||
|
||||
/** how many tunnels are we participating in? */
|
||||
public int getParticipatingCount();
|
||||
@@ -85,6 +88,7 @@ class DummyTunnelManagerFacade implements TunnelManagerFacade {
|
||||
public TunnelInfo selectOutboundTunnel() { return null; }
|
||||
public TunnelInfo selectOutboundTunnel(Hash destination) { return null; }
|
||||
public boolean isInUse(Hash peer) { return false; }
|
||||
public boolean isValidTunnel(Hash client, TunnelInfo tunnel) { return false; }
|
||||
public int getParticipatingCount() { return 0; }
|
||||
public int getFreeTunnelCount() { return 0; }
|
||||
public int getOutboundTunnelCount() { return 0; }
|
||||
|
@@ -4,6 +4,7 @@ import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* Wrap up the settings for a pool of tunnels (duh)
|
||||
@@ -14,7 +15,7 @@ public class TunnelPoolSettings {
|
||||
private String _destinationNickname;
|
||||
private int _quantity;
|
||||
private int _backupQuantity;
|
||||
private int _rebuildPeriod;
|
||||
// private int _rebuildPeriod;
|
||||
private int _duration;
|
||||
private int _length;
|
||||
private int _lengthVariance;
|
||||
@@ -22,7 +23,9 @@ public class TunnelPoolSettings {
|
||||
private boolean _isInbound;
|
||||
private boolean _isExploratory;
|
||||
private boolean _allowZeroHop;
|
||||
private int _IPRestriction;
|
||||
private Properties _unknownOptions;
|
||||
private Hash _randomKey;
|
||||
|
||||
/** prefix used to override the router's defaults for clients */
|
||||
public static final String PREFIX_DEFAULT = "router.defaultPool.";
|
||||
@@ -34,24 +37,26 @@ public class TunnelPoolSettings {
|
||||
public static final String PROP_NICKNAME = "nickname";
|
||||
public static final String PROP_QUANTITY = "quantity";
|
||||
public static final String PROP_BACKUP_QUANTITY = "backupQuantity";
|
||||
public static final String PROP_REBUILD_PERIOD = "rebuildPeriod";
|
||||
// public static final String PROP_REBUILD_PERIOD = "rebuildPeriod";
|
||||
public static final String PROP_DURATION = "duration";
|
||||
public static final String PROP_LENGTH = "length";
|
||||
public static final String PROP_LENGTH_VARIANCE = "lengthVariance";
|
||||
public static final String PROP_ALLOW_ZERO_HOP = "allowZeroHop";
|
||||
public static final String PROP_IP_RESTRICTION = "IPRestriction";
|
||||
|
||||
public static final int DEFAULT_QUANTITY = 2;
|
||||
public static final int DEFAULT_BACKUP_QUANTITY = 0;
|
||||
public static final int DEFAULT_REBUILD_PERIOD = 60*1000;
|
||||
// public static final int DEFAULT_REBUILD_PERIOD = 60*1000;
|
||||
public static final int DEFAULT_DURATION = 10*60*1000;
|
||||
public static final int DEFAULT_LENGTH = 2;
|
||||
public static final int DEFAULT_LENGTH_VARIANCE = 1;
|
||||
public static final boolean DEFAULT_ALLOW_ZERO_HOP = true;
|
||||
public static final int DEFAULT_IP_RESTRICTION = 2; // class B (/16)
|
||||
|
||||
public TunnelPoolSettings() {
|
||||
_quantity = DEFAULT_QUANTITY;
|
||||
_backupQuantity = DEFAULT_BACKUP_QUANTITY;
|
||||
_rebuildPeriod = DEFAULT_REBUILD_PERIOD;
|
||||
// _rebuildPeriod = DEFAULT_REBUILD_PERIOD;
|
||||
_duration = DEFAULT_DURATION;
|
||||
_length = DEFAULT_LENGTH;
|
||||
_lengthVariance = DEFAULT_LENGTH_VARIANCE;
|
||||
@@ -61,7 +66,9 @@ public class TunnelPoolSettings {
|
||||
_isExploratory = false;
|
||||
_destination = null;
|
||||
_destinationNickname = null;
|
||||
_IPRestriction = DEFAULT_IP_RESTRICTION;
|
||||
_unknownOptions = new Properties();
|
||||
_randomKey = generateRandomKey();
|
||||
}
|
||||
|
||||
/** how many tunnels should be available at all times */
|
||||
@@ -73,8 +80,8 @@ public class TunnelPoolSettings {
|
||||
public void setBackupQuantity(int quantity) { _backupQuantity = quantity; }
|
||||
|
||||
/** how long before tunnel expiration should new tunnels be built */
|
||||
public int getRebuildPeriod() { return _rebuildPeriod; }
|
||||
public void setRebuildPeriod(int periodMs) { _rebuildPeriod = periodMs; }
|
||||
// public int getRebuildPeriod() { return _rebuildPeriod; }
|
||||
// public void setRebuildPeriod(int periodMs) { _rebuildPeriod = periodMs; }
|
||||
|
||||
/** how many remote hops should be in the tunnel */
|
||||
public int getLength() { return _length; }
|
||||
@@ -112,10 +119,22 @@ public class TunnelPoolSettings {
|
||||
public Hash getDestination() { return _destination; }
|
||||
public void setDestination(Hash dest) { _destination = dest; }
|
||||
|
||||
/** random key used for peer ordering */
|
||||
public Hash getRandomKey() { return _randomKey; }
|
||||
|
||||
/** what user supplied name was given to the client connected (can be null) */
|
||||
public String getDestinationNickname() { return _destinationNickname; }
|
||||
public void setDestinationNickname(String name) { _destinationNickname = name; }
|
||||
|
||||
/**
|
||||
* How many bytes to match to determine if a router's IP is too close to another's
|
||||
* to be in the same tunnel
|
||||
* (1-4, 0 to disable)
|
||||
*
|
||||
*/
|
||||
public int getIPRestriction() { int r = _IPRestriction; if (r>4) r=4; else if (r<0) r=0; return r;}
|
||||
public void setIPRestriction(int b) { _IPRestriction = b; }
|
||||
|
||||
public Properties getUnknownOptions() { return _unknownOptions; }
|
||||
|
||||
public void readFromProperties(String prefix, Properties props) {
|
||||
@@ -135,10 +154,12 @@ public class TunnelPoolSettings {
|
||||
_lengthVariance = getInt(value, DEFAULT_LENGTH_VARIANCE);
|
||||
else if (name.equalsIgnoreCase(prefix + PROP_QUANTITY))
|
||||
_quantity = getInt(value, DEFAULT_QUANTITY);
|
||||
else if (name.equalsIgnoreCase(prefix + PROP_REBUILD_PERIOD))
|
||||
_rebuildPeriod = getInt(value, DEFAULT_REBUILD_PERIOD);
|
||||
// else if (name.equalsIgnoreCase(prefix + PROP_REBUILD_PERIOD))
|
||||
// _rebuildPeriod = getInt(value, DEFAULT_REBUILD_PERIOD);
|
||||
else if (name.equalsIgnoreCase(prefix + PROP_NICKNAME))
|
||||
_destinationNickname = value;
|
||||
else if (name.equalsIgnoreCase(prefix + PROP_IP_RESTRICTION))
|
||||
_IPRestriction = getInt(value, DEFAULT_IP_RESTRICTION);
|
||||
else
|
||||
_unknownOptions.setProperty(name.substring((prefix != null ? prefix.length() : 0)), value);
|
||||
}
|
||||
@@ -155,7 +176,8 @@ public class TunnelPoolSettings {
|
||||
if (_destinationNickname != null)
|
||||
props.setProperty(prefix + PROP_NICKNAME, ""+_destinationNickname);
|
||||
props.setProperty(prefix + PROP_QUANTITY, ""+_quantity);
|
||||
props.setProperty(prefix + PROP_REBUILD_PERIOD, ""+_rebuildPeriod);
|
||||
// props.setProperty(prefix + PROP_REBUILD_PERIOD, ""+_rebuildPeriod);
|
||||
props.setProperty(prefix + PROP_IP_RESTRICTION, ""+_IPRestriction);
|
||||
for (Iterator iter = _unknownOptions.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String val = _unknownOptions.getProperty(name);
|
||||
@@ -180,8 +202,12 @@ public class TunnelPoolSettings {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
////
|
||||
////
|
||||
// used for strict peer ordering
|
||||
private Hash generateRandomKey() {
|
||||
byte hash[] = new byte[Hash.HASH_LENGTH];
|
||||
RandomSource.getInstance().nextBytes(hash);
|
||||
return new Hash(hash);
|
||||
}
|
||||
|
||||
private static final boolean getBoolean(String str, boolean defaultValue) {
|
||||
if (str == null) return defaultValue;
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.router.message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -15,6 +16,7 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.PublicKey;
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.Payload;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
@@ -189,6 +191,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
_log.warn(getJobId() + ": Bundle leaseSet probability overridden incorrectly ["
|
||||
+ str + "]", nfe);
|
||||
}
|
||||
if (probability >= 100)
|
||||
return true;
|
||||
_log.error(getJobId() + ": Bundle leaseSet probability is " + probability);
|
||||
if (probability >= getContext().random().nextInt(100))
|
||||
return true;
|
||||
else
|
||||
@@ -198,7 +203,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/** send a message to a random lease */
|
||||
/** send a message to a lease */
|
||||
private class SendJob extends JobImpl {
|
||||
public SendJob(RouterContext enclosingContext) {
|
||||
super(enclosingContext);
|
||||
@@ -221,11 +226,22 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the same inbound tunnel (i.e. lease) as we did for the same destination previously,
|
||||
* if possible, to keep the streaming lib happy
|
||||
* Key the cache just on the dest, not on source+dest, as different sources
|
||||
* simultaneously talking to the same dest is probably rare enough
|
||||
* to not bother separating out.
|
||||
*
|
||||
* We're going to use the lease until it expires, as long as it remains in the current leaseSet.
|
||||
*
|
||||
* If not found,
|
||||
* fetch the next lease that we should try sending through, randomly chosen
|
||||
* from within the sorted leaseSet (sorted by # of failures through each
|
||||
* from within the sorted leaseSet (NOT sorted by # of failures through each
|
||||
* lease).
|
||||
*
|
||||
*/
|
||||
private static HashMap _leaseCache = new HashMap();
|
||||
private static long _lcleanTime = 0;
|
||||
private boolean getNextLease() {
|
||||
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
|
||||
if (_leaseSet == null) {
|
||||
@@ -234,7 +250,36 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
return false;
|
||||
}
|
||||
long now = getContext().clock().now();
|
||||
|
||||
|
||||
/*** removed until we fix SSU reachability
|
||||
// Use the same lease if it's still good
|
||||
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
|
||||
synchronized (_leaseCache) {
|
||||
if (now - _cleanTime > 5*60*1000) { // clean out periodically
|
||||
cleanLeaseCache(_leaseCache);
|
||||
_cleanTime = now;
|
||||
}
|
||||
_lease = (Lease) _leaseCache.get(_to);
|
||||
if (_lease != null) {
|
||||
// if outbound tunnel length == 0 && lease.firsthop.isBacklogged() don't use it ??
|
||||
if (!_lease.isExpired(Router.CLOCK_FUDGE_FACTOR)) {
|
||||
// see if the current leaseSet contains the old lease, so that if the dest removes
|
||||
// it (due to failure for example) we won't continue to use it.
|
||||
for (int i = 0; i < _leaseSet.getLeaseCount(); i++) {
|
||||
Lease lease = _leaseSet.getLease(i);
|
||||
if (_lease.equals(lease)) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Found in cache - lease for " + _toString);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Expired from cache - lease for " + _toString);
|
||||
_leaseCache.remove(_to);
|
||||
}
|
||||
}
|
||||
***/
|
||||
// get the possible leases
|
||||
List leases = new ArrayList(_leaseSet.getLeaseCount());
|
||||
for (int i = 0; i < _leaseSet.getLeaseCount(); i++) {
|
||||
@@ -258,6 +303,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
// sort are randomly ordered)
|
||||
Collections.shuffle(leases);
|
||||
|
||||
/****
|
||||
if (false) {
|
||||
// ordered by lease number of failures
|
||||
TreeMap orderedLeases = new TreeMap();
|
||||
@@ -273,8 +319,39 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
|
||||
_lease = (Lease)orderedLeases.get(orderedLeases.firstKey());
|
||||
} else {
|
||||
_lease = (Lease)leases.get(0);
|
||||
****/
|
||||
|
||||
|
||||
// Avoid a lease on a gateway we think is unreachable, if possible
|
||||
for (int i = 0; i < leases.size(); i++) {
|
||||
Lease l = (Lease) leases.get(i);
|
||||
/***
|
||||
*** Anonymity concerns with this, as the dest could act unreachable just to us, then
|
||||
*** look at our lease selection.
|
||||
*** Let's just look at whether the gw thinks it is unreachable instead -
|
||||
*** unfortunately the "U" is rarely seen.
|
||||
if (!getContext().commSystem().wasUnreachable(l.getGateway())) {
|
||||
***/
|
||||
RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(l.getGateway());
|
||||
if (ri == null || ri.getCapabilities().indexOf(Router.CAPABILITY_UNREACHABLE) < 0) {
|
||||
_lease = l;
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getJobId() + ": Skipping unreachable gateway " + l.getGateway() + " for " + _toString);
|
||||
}
|
||||
if (_lease == null) {
|
||||
_lease = (Lease)leases.get(0);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getJobId() + ": All leases are unreachable for " + _toString);
|
||||
}
|
||||
/*** removed until we fix SSU reachability
|
||||
synchronized (_leaseCache) {
|
||||
_leaseCache.put(_to, _lease);
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Added to cache - lease for " + _toString);
|
||||
***/
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -378,7 +455,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
+ _lease.getTunnelId() + " on "
|
||||
+ _lease.getGateway().toBase64());
|
||||
|
||||
_outTunnel = selectOutboundTunnel();
|
||||
_outTunnel = selectOutboundTunnel(_to);
|
||||
if (_outTunnel != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getJobId() + ": Sending tunnel message out " + _outTunnel.getSendTunnelId(0) + " to "
|
||||
@@ -434,6 +511,103 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean out old leases from a set.
|
||||
* Caller must synchronize on tc.
|
||||
*/
|
||||
private void cleanLeaseCache(HashMap tc) {
|
||||
List deleteList = new ArrayList();
|
||||
for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) {
|
||||
Destination dest = (Destination) iter.next();
|
||||
Lease l = (Lease) tc.get(dest);
|
||||
if (l.isExpired(Router.CLOCK_FUDGE_FACTOR))
|
||||
deleteList.add(dest);
|
||||
}
|
||||
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
|
||||
Destination dest = (Destination) iter.next();
|
||||
tc.remove(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean out old tunnels from a set.
|
||||
* Caller must synchronize on tc.
|
||||
*/
|
||||
private void cleanTunnelCache(HashMap tc) {
|
||||
List deleteList = new ArrayList();
|
||||
for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) {
|
||||
Destination dest = (Destination) iter.next();
|
||||
TunnelInfo tunnel = (TunnelInfo) tc.get(dest);
|
||||
if (!getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel))
|
||||
deleteList.add(dest);
|
||||
}
|
||||
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
|
||||
Destination dest = (Destination) iter.next();
|
||||
tc.remove(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the same outbound tunnel as we did for the same destination previously,
|
||||
* if possible, to keep the streaming lib happy
|
||||
* Use two caches - although a cache of a list of tunnels per dest might be
|
||||
* more elegant.
|
||||
* Key the caches just on the dest, not on source+dest, as different sources
|
||||
* simultaneously talking to the same dest is probably rare enough
|
||||
* to not bother separating out.
|
||||
*
|
||||
*/
|
||||
private static HashMap _tunnelCache = new HashMap();
|
||||
private static HashMap _backloggedTunnelCache = new HashMap();
|
||||
private static long _cleanTime = 0;
|
||||
private TunnelInfo selectOutboundTunnel(Destination to) {
|
||||
TunnelInfo tunnel;
|
||||
long now = getContext().clock().now();
|
||||
synchronized (_tunnelCache) {
|
||||
if (now - _cleanTime > 5*60*1000) { // clean out periodically
|
||||
cleanTunnelCache(_tunnelCache);
|
||||
cleanTunnelCache(_backloggedTunnelCache);
|
||||
_cleanTime = now;
|
||||
}
|
||||
/**
|
||||
* If old tunnel is valid and no longer backlogged, use it.
|
||||
* This prevents an active anonymity attack, where a peer could tell
|
||||
* if you were the originator by backlogging the tunnel, then removing the
|
||||
* backlog and seeing if traffic came back or not.
|
||||
*/
|
||||
tunnel = (TunnelInfo) _backloggedTunnelCache.get(to);
|
||||
if (tunnel != null) {
|
||||
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
|
||||
if (!getContext().commSystem().isBacklogged(tunnel.getPeer(1))) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Switching back to tunnel " + tunnel + " for " + _toString);
|
||||
_backloggedTunnelCache.remove(to);
|
||||
_tunnelCache.put(to, tunnel);
|
||||
return tunnel;
|
||||
} // else still backlogged
|
||||
} else // no longer valid
|
||||
_backloggedTunnelCache.remove(to);
|
||||
}
|
||||
// Use the same tunnel unless backlogged
|
||||
tunnel = (TunnelInfo) _tunnelCache.get(to);
|
||||
if (tunnel != null) {
|
||||
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
|
||||
if (tunnel.getLength() <= 1 || !getContext().commSystem().isBacklogged(tunnel.getPeer(1)))
|
||||
return tunnel;
|
||||
// backlogged
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Switching from backlogged " + tunnel + " for " + _toString);
|
||||
_backloggedTunnelCache.put(to, tunnel);
|
||||
} // else no longer valid
|
||||
_tunnelCache.remove(to);
|
||||
}
|
||||
// Pick a new tunnel
|
||||
tunnel = selectOutboundTunnel();
|
||||
if (tunnel != null)
|
||||
_tunnelCache.put(to, tunnel);
|
||||
}
|
||||
return tunnel;
|
||||
}
|
||||
/**
|
||||
* Pick an arbitrary outbound tunnel to send the message through, or null if
|
||||
* there aren't any around
|
||||
@@ -461,8 +635,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
|
||||
long sendTime = getContext().clock().now() - _start;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getJobId() + ": Failed to send the message " + _clientMessageId + " after "
|
||||
+ sendTime + "ms");
|
||||
_log.warn(getJobId() + ": Failed to send the message " + _clientMessageId + " to " + _toString +
|
||||
" out " + _outTunnel + " in " + _lease + " ack " + _inTunnel +
|
||||
" after " + sendTime + "ms");
|
||||
|
||||
long messageDelay = getContext().throttle().getMessageDelay();
|
||||
long tunnelLag = getContext().throttle().getTunnelLag();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user