10 Commits

Author SHA1 Message Date
zzz
22cf9e06ff 0.15.0 2017-03-11 18:23:14 +00:00
zzz
758c0865dc clean up warnings 2017-03-07 15:33:33 +00:00
zzz
ab14737fd1 For webapp also:
Pull in override.properties for bootclasspath
Bump to java 1.6
2016-08-14 15:38:58 +00:00
zzz
dd0d7ba6c9 Pull in override.properties for bootclasspath
Bump to java 1.6
2016-08-14 15:33:23 +00:00
zzz
d3ccdb5970 increase limits, set tag options 2016-06-13 16:34:35 +00:00
zzz
404ec7d720 update for 0.9.17 2016-06-13 16:34:18 +00:00
zzz
fa37064834 0.14.0 2015-05-28 13:00:07 +00:00
zzz
7cc2d97825 Remove use of deprecated SimpleScheduler
Remove static structures
Use RandomIterator for efficiency
untested
2015-04-16 22:33:50 +00:00
zzz
9ffef703b5 Increase startup delay, so it's after the eepsite Jetty,
so it doesn't create the static RolloverFileOutputStream Timer thread,
so PluginStarter doesn't think it's running after it stops.
2014-11-29 14:05:07 +00:00
zzz
5239dfb768 fix NPE on missing announce parameters 2014-11-26 20:52:58 +00:00
14 changed files with 362 additions and 127 deletions

View File

@ -1,3 +1,19 @@
0.15.0
2017-03-11
Increase default limits, set I2CP tag options
Update eepsite configuration for Jetty 9 (I2P 0.9.30)
0.14.0
2015-05-28
Remove use of deprecated SimpleScheduler (ticket #1523)
Remove static structures
Use RandomIterator for efficiency
0.13.0
2014-11-29
Fix NPE on missing announce parameters
Increase startup delay
0.12.0 0.12.0
2014-11-13 2014-11-13
Fix parameter decoding for scrape also Fix parameter decoding for scrape also

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<project basedir="." default="all" name="zzzot"> <project basedir="." default="all" name="zzzot">
<property file="override.properties"/>
<target name="all" depends="clean,plugin" /> <target name="all" depends="clean,plugin" />
@ -15,7 +16,7 @@
<delete dir="plugin/eepsite/docroot/torrents/" /> <delete dir="plugin/eepsite/docroot/torrents/" />
<!-- get version number --> <!-- get version number -->
<buildnumber file="scripts/build.number" /> <buildnumber file="scripts/build.number" />
<property name="release.number" value="0.12.0" /> <property name="release.number" value="0.15.0" />
<!-- make the update xpi2p --> <!-- make the update xpi2p -->
<!-- this contains everything except i2ptunnel.config --> <!-- this contains everything except i2ptunnel.config -->

View File

@ -2,7 +2,7 @@ clientApp.0.main=net.i2p.zzzot.ZzzOTController
clientApp.0.name=ZzzOT clientApp.0.name=ZzzOT
clientApp.0.args=-d $PLUGIN start clientApp.0.args=-d $PLUGIN start
clientApp.0.stopargs=-d $PLUGIN stop clientApp.0.stopargs=-d $PLUGIN stop
clientApp.0.delay=15 clientApp.0.delay=40
clientApp.0.startOnLoad=true clientApp.0.startOnLoad=true
# we also use i2p.jar and i2ptunnel.jar, they are in the standard router classpath # we also use i2p.jar and i2ptunnel.jar, they are in the standard router classpath
clientApp.0.classpath=$PLUGIN/lib/zzzot.jar,$I2P/lib/i2psnark.jar clientApp.0.classpath=$PLUGIN/lib/zzzot.jar,$I2P/lib/i2psnark.jar

View File

@ -15,10 +15,10 @@
<!-- * threads: Raise maximumPoolSize in the ThreadPool section --> <!-- * threads: Raise maximumPoolSize in the ThreadPool section -->
<!-- if you have a high-traffic site and get a lot of warnings. --> <!-- if you have a high-traffic site and get a lot of warnings. -->
<!-- --> <!-- -->
<!-- I2P uses Jetty 7. If you need web server features not found --> <!-- I2P uses Jetty 9. If you need web server features not found -->
<!-- in Jetty 7, you may install and run Jetty 7 or 8 in a different JVM --> <!-- in I2P's Jetty 9, you may install and run Jetty 9 in a different JVM -->
<!-- or run any other web server such as Apache. If you do run another web --> <!-- or run any other web server such as Apache. If you do run another web -->
<!-- server instead, be sure and disable the Jetty 6 server for your --> <!-- server instead, be sure and disable the Jetty 9 server for your -->
<!-- eepsite on http://127.0.0.1:7657/configclients.jsp . --> <!-- eepsite on http://127.0.0.1:7657/configclients.jsp . -->
<!-- --> <!-- -->
<!-- Jetty now uses the I2P logging system rather than wrapper.log. --> <!-- Jetty now uses the I2P logging system rather than wrapper.log. -->
@ -42,18 +42,18 @@
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Server Thread Pool --> <!-- Server Thread Pool -->
<!-- =========================================================== --> <!-- =========================================================== -->
<Set name="ThreadPool"> <Arg>
<!-- PICK ONE -->
<!-- <!--
Recommended.
Requests above the maxThreads + queue_size will be rejected and logged. Requests above the maxThreads + queue_size will be rejected and logged.
ref: ref:
https://wiki.eclipse.org/Jetty/Howto/High_Load https://wiki.eclipse.org/Jetty/Howto/High_Load
http://trac.i2p2.i2p/ticket/1395 http://trac.i2p2.i2p/ticket/1395
--> -->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Arg type="int">20</Arg> <!-- maxThreads, overridden below -->
<Arg type="int">3</Arg> <!-- minThreads, overridden below -->
<Arg type="int">60000</Arg> <!-- maxIdleTimeMs, overridden below -->
<Arg> <Arg>
<New class="java.util.concurrent.LinkedBlockingQueue"> <New class="java.util.concurrent.LinkedBlockingQueue">
<Arg type="int">50</Arg> <Arg type="int">50</Arg>
@ -61,43 +61,11 @@
</Arg> </Arg>
<Set name="minThreads">4</Set> <Set name="minThreads">4</Set>
<Set name="maxThreads">20</Set> <Set name="maxThreads">20</Set>
<Set name="maxIdleTimeMs">60000</Set> <Set name="idleTimeout">60000</Set>
<Set name="daemon">true</Set> <Set name="daemon">true</Set>
<Set name="name">Zzzot Jetty</Set> <Set name="name">Zzzot Jetty</Set>
</New> </New>
</Arg>
<!-- Optional Java 5 bounded threadpool with job queue
Requests above the max will be rejected and logged.
High-traffic sites should increase maximumPoolSize.
Args are:
corePoolSize (should be at least 3)
maximumPoolSize
keepAliveTime (milliseconds)
timeout (TimeUnit)
queue (BlockingQueue)
Not recommended.
ref:
http://trac.i2p2.i2p/ticket/1395
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html
-->
<!--
<New class="org.eclipse.jetty.util.thread.ExecutorThreadPool">
<Arg type="int">3</Arg>
<Arg type="int">20</Arg>
<Arg type="long">60000</Arg>
<Arg>
<Call class="java.util.concurrent.TimeUnit" name="valueOf" >
<Arg>MILLISECONDS</Arg>
</Call>
</Arg>
<Arg>
<New class="java.util.concurrent.SynchronousQueue" />
</Arg>
</New>
-->
</Set>
@ -116,38 +84,31 @@
--> -->
<Call name="addConnector"> <Call name="addConnector">
<Arg> <Arg>
<New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> <New class="org.eclipse.jetty.server.ServerConnector">
<Arg><Ref id="Server" /></Arg>
<Arg type="int">1</Arg> <!-- number of acceptors -->
<Arg type="int">0</Arg> <!-- default number of selectors -->
<Arg>
<Array type="org.eclipse.jetty.server.ConnectionFactory"> <!-- varargs so we need an array -->
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg>
<New class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="sendServerVersion">false</Set>
<Set name="sendDateHeader">true</Set>
</New>
</Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host">127.0.0.1</Set> <Set name="host">127.0.0.1</Set>
<Set name="port">7662</Set> <Set name="port">7662</Set>
<Set name="maxIdleTime">60000</Set> <Set name="idleTimeout">600000</Set>
<Set name="Acceptors">1</Set>
<Set name="statsOn">false</Set>
<Set name="confidentialPort">8443</Set>
<Set name="lowResourcesConnections">5000</Set>
<Set name="lowResourcesMaxIdleTime">5000</Set>
<Set name="useDirectBuffers">false</Set>
</New> </New>
</Arg> </Arg>
</Call> </Call>
<!-- Recommended to use this connector on Java 5, as
Jetty 6 and Java 5 NIO don't play well together.
-->
<!--
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.bio.SocketConnector">
<Set name="host">127.0.0.1</Set>
<Set name="port">7662</Set>
<Set name="maxIdleTime">60000</Set>
<Set name="Acceptors">1</Set>
<Set name="statsOn">false</Set>
<Set name="confidentialPort">8443</Set>
</New>
</Arg>
</Call>
-->
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Set up global session ID manager --> <!-- Set up global session ID manager -->
<!-- =========================================================== --> <!-- =========================================================== -->
@ -301,7 +262,7 @@
<Ref id="DeploymentManager"> <Ref id="DeploymentManager">
<Call name="addAppProvider"> <Call name="addAppProvider">
<Arg> <Arg>
<New class="org.eclipse.jetty.deploy.providers.ContextProvider"> <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDirName">$PLUGIN/contexts</Set> <Set name="monitoredDirName">$PLUGIN/contexts</Set>
<Set name="scanInterval">120</Set> <Set name="scanInterval">120</Set>
</New> </New>
@ -381,8 +342,6 @@
<!-- extra options --> <!-- extra options -->
<!-- =========================================================== --> <!-- =========================================================== -->
<Set name="stopAtShutdown">true</Set> <Set name="stopAtShutdown">true</Set>
<Set name="sendServerVersion">false</Set> <Set name="stopTimeout">1000</Set>
<Set name="sendDateHeader">true</Set>
<Set name="gracefulShutdown">1000</Set>
</Configure> </Configure>

View File

@ -2,27 +2,29 @@ tunnel.0.description=ZzzOT
tunnel.0.i2cpHost=127.0.0.1 tunnel.0.i2cpHost=127.0.0.1
tunnel.0.i2cpPort=7654 tunnel.0.i2cpPort=7654
tunnel.0.name=zzzot tunnel.0.name=zzzot
tunnel.0.option.crypto.lowTagThreshold=4
tunnel.0.option.crypto.tagsToSend=10
tunnel.0.option.i2cp.enableAccessList=false tunnel.0.option.i2cp.enableAccessList=false
tunnel.0.option.i2cp.encryptLeaseSet=false tunnel.0.option.i2cp.encryptLeaseSet=false
tunnel.0.option.i2cp.reduceIdleTime=1200000 tunnel.0.option.i2cp.reduceIdleTime=1200000
tunnel.0.option.i2cp.reduceOnIdle=true tunnel.0.option.i2cp.reduceOnIdle=true
tunnel.0.option.i2cp.reduceQuantity=1 tunnel.0.option.i2cp.reduceQuantity=1
tunnel.0.option.i2p.streaming.connectDelay=0 tunnel.0.option.i2p.streaming.connectDelay=0
tunnel.0.option.i2p.streaming.maxConcurrentStreams=40 tunnel.0.option.i2p.streaming.maxConcurrentStreams=80
tunnel.0.option.i2p.streaming.maxConnsPerHour=100 tunnel.0.option.i2p.streaming.maxConnsPerHour=300
tunnel.0.option.i2p.streaming.maxConnsPerMinute=10 tunnel.0.option.i2p.streaming.maxConnsPerMinute=20
tunnel.0.option.i2p.streaming.maxTotalConnsPerHour=2500 tunnel.0.option.i2p.streaming.maxTotalConnsPerHour=50000
tunnel.0.option.i2p.streaming.maxTotalConnsPerMinute=60 tunnel.0.option.i2p.streaming.maxTotalConnsPerMinute=2000
tunnel.0.option.inbound.backupQuantity=0 tunnel.0.option.inbound.backupQuantity=0
tunnel.0.option.inbound.length=3 tunnel.0.option.inbound.length=3
tunnel.0.option.inbound.lengthVariance=0 tunnel.0.option.inbound.lengthVariance=0
tunnel.0.option.inbound.nickname=ZzzOT tunnel.0.option.inbound.nickname=ZzzOT
tunnel.0.option.inbound.quantity=2 tunnel.0.option.inbound.quantity=3
tunnel.0.option.outbound.backupQuantity=0 tunnel.0.option.outbound.backupQuantity=0
tunnel.0.option.outbound.length=3 tunnel.0.option.outbound.length=3
tunnel.0.option.outbound.lengthVariance=0 tunnel.0.option.outbound.lengthVariance=0
tunnel.0.option.outbound.nickname=ZzzOT tunnel.0.option.outbound.nickname=ZzzOT
tunnel.0.option.outbound.quantity=2 tunnel.0.option.outbound.quantity=3
tunnel.0.privKeyFile=plugins/zzzot/eepPriv.dat tunnel.0.privKeyFile=plugins/zzzot/eepPriv.dat
tunnel.0.startOnLoad=true tunnel.0.startOnLoad=true
tunnel.0.targetHost=127.0.0.1 tunnel.0.targetHost=127.0.0.1

View File

@ -8,6 +8,5 @@ updateURL=http://stats.i2p/i2p/plugins/zzzot-update.xpi2p
updateURL.su3=http://stats.i2p/i2p/plugins/zzzot-update.su3 updateURL.su3=http://stats.i2p/i2p/plugins/zzzot-update.su3
websiteURL=http://zzz.i2p/forums/16 websiteURL=http://zzz.i2p/forums/16
license=Apache 2.0 license=Apache 2.0
min-jetty-version=7 min-jetty-version=9
max-jetty-version=8.9999 min-i2p-version=0.9.29
min-i2p-version=0.9.9

View File

@ -25,13 +25,14 @@
</target> </target>
<property name="javac.compilerargs" value="" /> <property name="javac.compilerargs" value="" />
<property name="javac.version" value="1.7" />
<target name="compile"> <target name="compile">
<mkdir dir="./build" /> <mkdir dir="./build" />
<mkdir dir="./build/obj" /> <mkdir dir="./build/obj" />
<javac <javac
srcdir="./java" srcdir="./java"
debug="true" deprecation="on" source="1.5" target="1.5" debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
destdir="./build/obj" destdir="./build/obj"
includeAntRuntime="false" includeAntRuntime="false"
classpath="${i2plib}/i2p.jar:${i2plib}/i2ptunnel.jar:${i2plib}/i2psnark.jar:${i2plib}/mstreaming.jar:${i2plib}/systray.jar:${jettylib}/org.mortbay.jetty.jar:${jettylib}/jetty-util.jar:${jettylib}/jetty-xml.jar" > classpath="${i2plib}/i2p.jar:${i2plib}/i2ptunnel.jar:${i2plib}/i2psnark.jar:${i2plib}/mstreaming.jar:${i2plib}/systray.jar:${jettylib}/org.mortbay.jetty.jar:${jettylib}/jetty-util.jar:${jettylib}/jetty-xml.jar" >
@ -66,13 +67,15 @@
<javac <javac
debug="true" debug="true"
deprecation="on" deprecation="on"
source="1.5" target="1.5" source="${javac.version}" target="${javac.version}"
destdir="build/war/WEB-INF/classes" destdir="build/war/WEB-INF/classes"
srcdir="./build/jspjava" srcdir="./build/jspjava"
includes="**/*.java" includes="**/*.java"
includeAntRuntime="false" includeAntRuntime="false"
classpathref="jspcp" classpathref="jspcp"
failonerror="true" /> failonerror="true" >
<compilerarg line="${javac.compilerargs}" />
</javac>
<copy file="jsp/WEB-INF/web.xml" tofile="build/web.xml" /> <copy file="jsp/WEB-INF/web.xml" tofile="build/web.xml" />
<loadfile property="jspc.web.fragment" srcfile="build/web-fragment.xml" /> <loadfile property="jspc.web.fragment" srcfile="build/web-fragment.xml" />

View File

@ -18,14 +18,12 @@ package net.i2p.zzzot;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap;
import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SHA256Generator;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
/* /*
* A single peer for a single torrent. * A single peer for a single torrent.
@ -38,15 +36,9 @@ public class Peer extends HashMap<String, Object> {
private long lastSeen; private long lastSeen;
private long bytesLeft; private long bytesLeft;
private static final ConcurrentHashMap<String, String> destCache = new ConcurrentHashMap();
private static final Integer PORT = Integer.valueOf(6881); private static final Integer PORT = Integer.valueOf(6881);
private static final long CLEAN_TIME = 3*60*60*1000;
static { public Peer(byte[] id, Destination address, ConcurrentMap<String, String> destCache) {
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
}
public Peer(byte[] id, Destination address) {
super(3); super(3);
if (id.length != 20) if (id.length != 20)
throw new IllegalArgumentException("Bad peer ID length: " + id.length); throw new IllegalArgumentException("Bad peer ID length: " + id.length);
@ -83,10 +75,4 @@ public class Peer extends HashMap<String, Object> {
return new String(h.getData(), "ISO-8859-1"); return new String(h.getData(), "ISO-8859-1");
} catch (UnsupportedEncodingException uee) { return null; } } catch (UnsupportedEncodingException uee) { return null; }
} }
private static class Cleaner implements SimpleTimer.TimedEvent {
public void timeReached() {
destCache.clear();
}
}
} }

View File

@ -0,0 +1,225 @@
package net.i2p.zzzot;
/*
* Modified from:
* http://www.lockergnome.com/awarberg/2007/04/22/random-iterator-in-java/
* No license, free to use
*/
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Random;
import net.i2p.util.RandomSource;
import net.i2p.util.SystemVersion;
/**
* Copied from net.i2p.router.util
*
* This is some Java code I wrote for a school project to save some time when iterating in
* random order over a part of list (until some condition becomes true):
*
* Here is a sample on how to use the code:
*
<pre>
for(Iterator<Object> iter = new RandomIterator<Object>(myObjList); iter.hasNext();){
Object o = iter.next();
if(someCondition(o) )
return o; // iteration stopped early
}
</pre>
*
* I wrote it to replace a Collection.shuffle call and this code gave us an overall increase in program execution speed of about 25%.
* As the javadoc description says, you are better off calling Collection.shuffle if you need to iterate over the entire list. But if you may stop early this class can save you some time, as it did in our case.
*
* Provides a random iteration over the given list.
*
* This effect can be achieved by using Collections.shuffle,
* which shuffles the entire collection in linear time.
*
* If the iteration process may end before all items
* are processed, this class may give a speed increase
* because the shuffling process is performed as items are requested
* rather than in the beginning.
*
* I2P changes:
*<pre>
* - Use BitSet instead of boolean[]
* - Use I2P RandomSource
* - Done check in next(), throw NSEE
* - Ensure lower and upper bounds are always clear
* - Replace unbounded loop in next(). It is now O(N) time, but now
* the iterator will tend to "clump" results and thus is not truly random.
* *** This class is not recommended for small Lists,
* *** or for iterating through a large portion of a List.
* *** Use Collections.shuffle() instead.
* - Add test code
*</pre>
*
* @since zzzot 0.14.0
*/
public class RandomIterator<E> implements Iterator<E> {
/**
* Mapping indicating which items were served (by index).
* if served[i] then the item with index i in the list
* has already been served.
*
* Note it is possible to save memory here by using
* BitSet rather than a boolean array, however it will
* increase the running time slightly.
*/
private final BitSet served;
/** The amount of items served so far */
private int servedCount = 0;
private final List<E> list;
private final int LIST_SIZE;
/**
* The random number generator has a great influence
* on the running time of this iterator.
*
* See, for instance,
* <a href="http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation" title="http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation" target="_blank">http://www.qbrundage.com/michaelb/pubs/e&#8230;</a>
* for some implementations, which are faster than java.util.Random.
*/
private final Random rand = RandomSource.getInstance();
/** Used to narrow the range to take random indexes from */
private int lower, upper;
private static final boolean hasAndroidBug;
static {
if (SystemVersion.isAndroid()) {
// only present on Gingerbread (API 11), but set if version check failed also
int ver = SystemVersion.getAndroidVersion();
hasAndroidBug = ver == 11 || ver == 0;
if (hasAndroidBug)
testAndroid();
} else {
hasAndroidBug = false;
}
}
public RandomIterator(List<E> list){
this.list = list;
LIST_SIZE = list.size();
served = new BitSet(LIST_SIZE);
upper = LIST_SIZE - 1;
}
public boolean hasNext() {
return servedCount < LIST_SIZE;
}
public E next() {
if (!hasNext())
throw new NoSuchElementException();
int range = upper - lower + 1;
// This has unbounded behavior, even with lower/upper
//int index;
//do {
// index = lower + rand.nextInt(range);
//} while (served.get(index));
// This tends to "clump" results, escpecially toward the end of the iteration.
// It also tends to leave the first and last few elements until the end.
int start = lower + rand.nextInt(range);
int index;
if ((start % 2) == 0) // coin flip
index = served.nextClearBit(start);
else
index = previousClearBit(start);
if (index < 0)
throw new NoSuchElementException("shouldn't happen");
servedCount++;
served.set(index);
// check if the range from which random values
// are taken can be reduced
// I2P - ensure lower and upper are always clear
if (hasNext()) {
if (index == lower)
// workaround for Android ICS bug - see below
lower = hasAndroidBug ? nextClearBit(index) : served.nextClearBit(index);
else if (index == upper)
upper = previousClearBit(index - 1);
}
return list.get(index);
}
/** just like nextClearBit() */
private int previousClearBit(int n) {
for (int i = n; i >= lower; i--) {
if (!served.get(i)) {
return i;
}
}
return -1;
}
/**
* Workaround for bug in Android (ICS only?)
* http://code.google.com/p/android/issues/detail?id=31036
* @since 0.9.2
*/
private int nextClearBit(int n) {
for (int i = n; i <= upper; i++) {
if (!served.get(i)) {
return i;
}
}
return -1;
}
/**
* @throws UnsupportedOperationException always
*/
public void remove() {
throw new UnsupportedOperationException();
}
/****
public static void main(String[] args) {
testAndroid();
test(0);
test(1);
test(2);
test(1000);
}
private static void test(int n) {
System.out.println("testing with " + n);
List<Integer> l = new ArrayList<Integer>(n);
for (int i = 0; i < n; i++) {
l.add(Integer.valueOf(i));
}
for (Iterator<Integer> iter = new RandomIterator<Integer>(l); iter.hasNext(); ) {
System.out.println(iter.next().toString());
}
}
****/
/**
* Test case from android ticket above
* @since 0.9.2
*/
private static void testAndroid() {
System.out.println("Checking for Android BitSet bug");
BitSet theBitSet = new BitSet(864);
for (int exp =0; exp < 864; exp++) {
int act = theBitSet.nextClearBit(0);
if (exp != act) {
System.err.println(String.format("Test failed for: exp=%d, act=%d", exp, act));
System.err.println("Android BitSet bug detected, workaround implemented!");
return;
}
theBitSet.set(exp);
}
System.err.println("Android BitSet bug NOT detected, no workaround needed!");
}
}

View File

@ -18,6 +18,8 @@ package net.i2p.zzzot;
import java.util.Iterator; import java.util.Iterator;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.util.SimpleTimer2; import net.i2p.util.SimpleTimer2;
@ -29,10 +31,12 @@ class ZzzOT {
private final Torrents _torrents; private final Torrents _torrents;
private final Cleaner _cleaner; private final Cleaner _cleaner;
private final ConcurrentHashMap<String, String> _destCache = new ConcurrentHashMap<String, String>();
private final long EXPIRE_TIME; private final long EXPIRE_TIME;
private static final String PROP_INTERVAL = "interval"; private static final String PROP_INTERVAL = "interval";
private static final long CLEAN_TIME = 4*60*1000; private static final long CLEAN_TIME = 4*60*1000;
private static final long DEST_CACHE_CLEAN_TIME = 3*60*60*1000;
private static final int DEFAULT_INTERVAL = 27*60; private static final int DEFAULT_INTERVAL = 27*60;
private static final int MIN_INTERVAL = 15*60; private static final int MIN_INTERVAL = 15*60;
private static final int MAX_INTERVAL = 6*60*60; private static final int MAX_INTERVAL = 6*60*60;
@ -58,6 +62,11 @@ class ZzzOT {
return _torrents; return _torrents;
} }
/** @since 0.9.14 */
ConcurrentHashMap<String, String> getDestCache() {
return _destCache;
}
void start() { void start() {
_cleaner.forceReschedule(CLEAN_TIME); _cleaner.forceReschedule(CLEAN_TIME);
} }
@ -65,10 +74,13 @@ class ZzzOT {
void stop() { void stop() {
_cleaner.cancel(); _cleaner.cancel();
_torrents.clear(); _torrents.clear();
_destCache.clear();
} }
private class Cleaner extends SimpleTimer2.TimedEvent { private class Cleaner extends SimpleTimer2.TimedEvent {
private final AtomicInteger _runCount = new AtomicInteger();
/** must schedule later */ /** must schedule later */
public Cleaner(I2PAppContext ctx) { public Cleaner(I2PAppContext ctx) {
super(ctx.simpleTimer2()); super(ctx.simpleTimer2());
@ -89,6 +101,9 @@ class ZzzOT {
if (recent <= 0) if (recent <= 0)
iter.remove(); iter.remove();
} }
if (_runCount.incrementAndGet() % (DEST_CACHE_CLEAN_TIME / CLEAN_TIME) == 0) {
_destCache.clear();
}
schedule(CLEAN_TIME); schedule(CLEAN_TIME);
} }
} }

View File

@ -21,6 +21,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentMap;
import net.i2p.CoreVersion; import net.i2p.CoreVersion;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
@ -69,7 +70,7 @@ public class ZzzOTController implements ClientApp {
private static final String NAME = "ZzzOT"; private static final String NAME = "ZzzOT";
private static final String CONFIG_FILE = "zzzot.config"; private static final String CONFIG_FILE = "zzzot.config";
private static final String BACKUP_SUFFIX = ".jetty6"; private static final String BACKUP_SUFFIX = ".jetty8";
private static final String[] xmlFiles = { private static final String[] xmlFiles = {
"jetty.xml", "contexts/base-context.xml", "contexts/cgi-context.xml", "jetty.xml", "contexts/base-context.xml", "contexts/cgi-context.xml",
"etc/realm.properties", "etc/webdefault.xml" }; "etc/realm.properties", "etc/webdefault.xml" };
@ -119,6 +120,22 @@ public class ZzzOTController implements ClientApp {
return ctrlr._zzzot.getTorrents(); return ctrlr._zzzot.getTorrents();
} }
/**
* @return null if not running
* @since 0.9.14
*/
public static ConcurrentMap<String, String> getDestCache() {
ClientAppManager mgr = I2PAppContext.getGlobalContext().clientAppManager();
if (mgr == null)
return null;
ClientApp z = mgr.getRegisteredApp(NAME);
if (z == null)
return null;
ZzzOTController ctrlr = (ZzzOTController) z;
return ctrlr._zzzot.getDestCache();
}
/** /**
* @param args ignored * @param args ignored
*/ */
@ -211,11 +228,8 @@ public class ZzzOTController implements ClientApp {
if (_tunnel == null) if (_tunnel == null)
return; return;
try { try {
// destroyTunnel() not available until 0.9.17, but we put 0.9.16 here for now // destroyTunnel() not available until 0.9.17
// so we get testing in 0.9.16-6 or later dev builds. if (VersionComparator.comp(CoreVersion.VERSION, "0.9.17") >= 0) {
// No access to RouterVersion here.
// TODO change to 0.9.17
if (VersionComparator.comp(CoreVersion.VERSION, "0.9.16") >= 0) {
try { try {
_tunnel.destroyTunnel(); _tunnel.destroyTunnel();
} catch (Throwable t) { } catch (Throwable t) {
@ -266,10 +280,10 @@ public class ZzzOTController implements ClientApp {
* @since 0.10 (Jetty 7) * @since 0.10 (Jetty 7)
*/ */
private static boolean shouldMigrate(File f) { private static boolean shouldMigrate(File f) {
String xml = FileUtil.readTextFile(f.getAbsolutePath(), 100, true); String xml = FileUtil.readTextFile(f.getAbsolutePath(), 400, true);
if (xml == null) if (xml == null)
return true; return true;
return xml.contains("class=\"org.mortbay.jetty.Server\""); return xml.contains("class=\"org.eclipse.jetty.server.nio.SelectChannelConnector\"");
} }
/** /**

View File

@ -1,4 +1,4 @@
<%@page import="java.io.ByteArrayInputStream,java.util.ArrayList,java.util.Collections,java.util.List,java.util.Map,java.util.HashMap,net.i2p.data.Base64,net.i2p.data.Destination,net.i2p.zzzot.*,org.klomp.snark.bencode.BEncoder" %><% <%@page import="java.io.ByteArrayInputStream,java.util.ArrayList,java.util.Collections,java.util.List,java.util.Map,java.util.HashMap,java.util.concurrent.ConcurrentMap,net.i2p.data.Base64,net.i2p.data.Destination,net.i2p.zzzot.*,org.klomp.snark.bencode.BEncoder" %><%
/* /*
* Above one-liner is so there is no whitespace -> IllegalStateException * Above one-liner is so there is no whitespace -> IllegalStateException
@ -64,7 +64,8 @@
if (xff != null || xfs != null) { if (xff != null || xfs != null) {
fail = true; fail = true;
msg = "Non-I2P access denied"; msg = "Non-I2P access denied";
response.setStatus(403, msg); //response.setStatus(403, msg);
response.setStatus(403);
} }
if (info_hash == null && !fail) { if (info_hash == null && !fail) {
@ -72,7 +73,7 @@
msg = "no info hash"; msg = "no info hash";
} }
if (info_hash.length() != 20 && !fail) { if (!fail && info_hash.length() != 20) {
fail = true; fail = true;
msg = "bad info hash length " + info_hash.length(); msg = "bad info hash length " + info_hash.length();
} }
@ -87,7 +88,7 @@
msg = "no peer id"; msg = "no peer id";
} }
if (peer_id.length() != 20 && !fail) { if (!fail && peer_id.length() != 20) {
fail = true; fail = true;
msg = "bad peer id length " + peer_id.length(); msg = "bad peer id length " + peer_id.length();
} }
@ -177,7 +178,7 @@
} catch (NumberFormatException nfe) {}; } catch (NumberFormatException nfe) {};
} }
Map<String, Object> m = new HashMap(8); Map<String, Object> m = new HashMap<String, Object>(8);
if (fail) { if (fail) {
m.put("failure reason", msg); m.put("failure reason", msg);
} else if ("stopped".equals(event)) { } else if ("stopped".equals(event)) {
@ -197,7 +198,8 @@
// fixme same peer id, different dest // fixme same peer id, different dest
Peer p = peers.get(pid); Peer p = peers.get(pid);
if (p == null) { if (p == null) {
p = new Peer(pid.getData(), d); ConcurrentMap<String, String> destCache = ZzzOTController.getDestCache();
p = new Peer(pid.getData(), d, destCache);
// don't add if spoofed // don't add if spoofed
if (matchIP) { if (matchIP) {
Peer p2 = peers.putIfAbsent(pid, p); Peer p2 = peers.putIfAbsent(pid, p);
@ -218,11 +220,20 @@
// snark < 0.7.13 always wants a list // snark < 0.7.13 always wants a list
m.put("peers", java.util.Collections.EMPTY_LIST); m.put("peers", java.util.Collections.EMPTY_LIST);
} else { } else {
List<Peer> peerlist = new ArrayList(peers.values()); List<Peer> peerlist = new ArrayList<Peer>(peers.values());
peerlist.remove(p); // them peerlist.remove(p); // them
if (want < size - 1) { if (want < size - 1) {
Collections.shuffle(peerlist); if (size > 150) {
peerlist = peerlist.subList(0, want); // If size is huge, use random iterator for efficiency
List<Peer> rv = new ArrayList<Peer>(size);
for (RandomIterator<Peer> iter = new RandomIterator<Peer>(peerlist); iter.hasNext(); ) {
rv.add(iter.next());
}
peerlist = rv;
} else {
Collections.shuffle(peerlist);
peerlist = peerlist.subList(0, want);
}
} }
if (compact) { if (compact) {
// old experimental way - list of hashes // old experimental way - list of hashes

View File

@ -45,7 +45,8 @@
if (xff != null || xfs != null) { if (xff != null || xfs != null) {
fail = true; fail = true;
msg = "Non-I2P access denied"; msg = "Non-I2P access denied";
response.setStatus(403, msg); //response.setStatus(403, msg);
response.setStatus(403);
} }
boolean all = info_hash == null; boolean all = info_hash == null;
@ -67,21 +68,21 @@
} }
// build 3-level dictionary // build 3-level dictionary
Map<String, Object> m = new HashMap(4); Map<String, Object> m = new HashMap<String, Object>(4);
if (fail) { if (fail) {
m.put("failure reason", msg); m.put("failure reason", msg);
} else { } else {
List<InfoHash> ihList = new ArrayList(); List<InfoHash> ihList = new ArrayList<InfoHash>();
if (all) if (all)
ihList.addAll(torrents.keySet()); ihList.addAll(torrents.keySet());
else else
ihList.add(ih); ihList.add(ih);
Map<String, Map> files = new HashMap(); Map<String, Map> files = new HashMap<String, Map>();
for (InfoHash ihash : ihList) { for (InfoHash ihash : ihList) {
Peers peers = torrents.get(ihash); Peers peers = torrents.get(ihash);
if (peers == null) if (peers == null)
continue; continue;
Map<String, Object> dict = new HashMap(); Map<String, Object> dict = new HashMap<String, Object>();
int size = peers.size(); int size = peers.size();
int seeds = peers.countSeeds(); int seeds = peers.countSeeds();
dict.put("complete", Integer.valueOf(seeds)); dict.put("complete", Integer.valueOf(seeds));

View File

@ -40,7 +40,8 @@
if (xff != null || xfs != null) { if (xff != null || xfs != null) {
String msg = "Non-I2P access denied"; String msg = "Non-I2P access denied";
response.setStatus(403, msg); //response.setStatus(403, msg);
response.setStatus(403);
out.println(msg); out.println(msg);
} else if (req == null) { } else if (req == null) {
// probe // probe
@ -63,7 +64,8 @@
// all the peers // all the peers
Torrents torrents = ZzzOTController.getTorrents(); Torrents torrents = ZzzOTController.getTorrents();
if (torrents == null) { if (torrents == null) {
response.setStatus(503, "Down"); //response.setStatus(503, "Down");
response.setStatus(503);
return; return;
} }
for (InfoHash ihash : torrents.keySet()) { for (InfoHash ihash : torrents.keySet()) {
@ -92,7 +94,8 @@
} }
} else { } else {
// error code // error code
response.setStatus(406, "Bad request"); //response.setStatus(406, "Bad request");
response.setStatus(406);
out.println("SC_NOT_ACCEPTABLE"); out.println("SC_NOT_ACCEPTABLE");
} }