Compare commits
26 Commits
zzzot-0.8
...
zzzot-0.15
Author | SHA1 | Date | |
---|---|---|---|
22cf9e06ff | |||
758c0865dc | |||
ab14737fd1 | |||
dd0d7ba6c9 | |||
d3ccdb5970 | |||
404ec7d720 | |||
fa37064834 | |||
7cc2d97825 | |||
9ffef703b5 | |||
5239dfb768 | |||
953533c6e3 | |||
2e0f7ae4bf | |||
17e5595dd0 | |||
8350d009d4 | |||
a7225a2379 | |||
8a9094cd8e | |||
7f4394aa0f | |||
38f38398ef | |||
8317e3ce9a | |||
c1f6a14367 | |||
7e36455b05 | |||
a85aa6af31 | |||
f33303f394 | |||
ab882f8582 | |||
ce7562c547 | |||
52d8e26ffc |
82
CHANGES.txt
Normal file
82
CHANGES.txt
Normal file
@ -0,0 +1,82 @@
|
||||
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
|
||||
2014-11-13
|
||||
Fix parameter decoding for scrape also
|
||||
Add caching for info hashes and peer ids
|
||||
Stop cleaner when plugin stops
|
||||
Move to the ClientApp interface, remove all static refs
|
||||
Attempt to fix crash after update
|
||||
Add zzzot.config file to set interval
|
||||
Don't overwrite index.html and robots.txt in the update
|
||||
Release all resources when shut down (requires 0.9.16-6 or higher)
|
||||
|
||||
0.11.0
|
||||
2014-11-11
|
||||
Critical fix for announce parameter decoding, triggered by recent Jetty versions
|
||||
Change request queueing in jetty.xml (new installs only)
|
||||
SU3 plugin file format
|
||||
|
||||
0.10.0
|
||||
2013-04-14
|
||||
Updates and migration for Jetty 7 (I2P 0.9.6)
|
||||
|
||||
0.9.0
|
||||
2013-01-25
|
||||
Add cache-control directives
|
||||
Set max Jetty to 6.99999
|
||||
|
||||
0.8
|
||||
2012-03-10
|
||||
fix comment in jetty.xml
|
||||
|
||||
0.7
|
||||
2012-03-10
|
||||
Port to Jetty 6
|
||||
Replace QForwardHandler with RewriteHandler
|
||||
Use ${ant.home}/lib/ant.jar instead of pulling ant.jar from Jetty
|
||||
|
||||
0.6
|
||||
2011-12-31
|
||||
Set max jetty version 5.99999
|
||||
Add throttle options
|
||||
Stub out announce-to-seedless
|
||||
Seedless fixes, untested
|
||||
|
||||
0.5
|
||||
2010-07-11
|
||||
Final compact response format
|
||||
|
||||
0.4
|
||||
2010-07-09
|
||||
Compact request/response support - may not be final format
|
||||
Fix NPE if no ip parameter
|
||||
|
||||
0.3
|
||||
2010-04-13
|
||||
Verify dest
|
||||
Add xfs check
|
||||
|
||||
0.2
|
||||
2010-03-23
|
||||
Cache b64 dest strings
|
||||
Help typo fix (thx duck)
|
||||
Lots of seedless fixes
|
||||
Build cleanups
|
||||
|
||||
0.1
|
||||
2010-03-23
|
35
build.xml
35
build.xml
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project basedir="." default="all" name="zzzot">
|
||||
<property file="override.properties"/>
|
||||
|
||||
<target name="all" depends="clean,plugin" />
|
||||
|
||||
@ -8,10 +9,14 @@
|
||||
</target>
|
||||
|
||||
<target name="plugin" depends="war">
|
||||
<delete file="plugin/i2ptunnel.config" />
|
||||
<delete>
|
||||
<!-- in installer but not update -->
|
||||
<fileset dir="plugin/" includes="i2ptunnel.config zzzot.config eepsite/docroot/index.html eepsite/docroot/robots.txt" />
|
||||
</delete>
|
||||
<delete dir="plugin/eepsite/docroot/torrents/" />
|
||||
<!-- get version number -->
|
||||
<buildnumber file="scripts/build.number" />
|
||||
<property name="release.number" value="0.8" />
|
||||
<property name="release.number" value="0.15.0" />
|
||||
|
||||
<!-- make the update xpi2p -->
|
||||
<!-- this contains everything except i2ptunnel.config -->
|
||||
@ -34,18 +39,31 @@
|
||||
<arg value="plugin/eepsite/webapps/tracker.war.pack" />
|
||||
<arg value="src/build/tracker.war.jar" />
|
||||
</exec>
|
||||
<exec executable="scripts/makeplugin.sh" failonerror="true" >
|
||||
<input message="Enter su3 signing key password:" addproperty="release.password.su3" />
|
||||
<fail message="You must enter a password." >
|
||||
<condition>
|
||||
<equals arg1="${release.password.su3}" arg2=""/>
|
||||
</condition>
|
||||
</fail>
|
||||
<!-- this will fail if no su3 keys exist, as it needs the password twice -->
|
||||
<exec executable="scripts/makeplugin.sh" inputstring="${release.password.su3}" failonerror="true" >
|
||||
<arg value="plugin" />
|
||||
</exec>
|
||||
<move file="zzzot.xpi2p" tofile="zzzot-update.xpi2p" overwrite="true" />
|
||||
<move file="zzzot.su3" tofile="zzzot-update.su3" overwrite="true" />
|
||||
|
||||
<!-- make the install xpi2p -->
|
||||
<copy file="scripts/i2ptunnel.config" todir="plugin/" overwrite="true" />
|
||||
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
|
||||
<!-- Files in installer but not update. Be sure to Add to delete fileset above and clean target below -->
|
||||
<copy file="scripts/i2ptunnel.config" todir="plugin/" overwrite="true" />
|
||||
<copy file="scripts/zzzot.config" todir="plugin/" overwrite="true" />
|
||||
<copy file="scripts/index.html" todir="plugin/eepsite/docroot/" overwrite="true" />
|
||||
<copy file="scripts/robots.txt" todir="plugin/eepsite/docroot/" overwrite="true" />
|
||||
<mkdir dir="plugin/eepsite/docroot/torrents/" />
|
||||
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||
<arg value="version=${release.number}-b${build.number}" />
|
||||
</exec>
|
||||
<exec executable="scripts/makeplugin.sh" failonerror="true" >
|
||||
<exec executable="scripts/makeplugin.sh" inputstring="${release.password.su3}" failonerror="true" >
|
||||
<arg value="plugin" />
|
||||
</exec>
|
||||
</target>
|
||||
@ -56,12 +74,19 @@
|
||||
<ant dir="src" target="clean" />
|
||||
<delete file="plugin/i2ptunnel.config" />
|
||||
<delete file="plugin/plugin.config" />
|
||||
<delete file="plugin/zzzot.config" />
|
||||
<delete file="plugin/eepsite/docroot/index.html" />
|
||||
<delete file="plugin/eepsite/docroot/robots.txt" />
|
||||
<delete file="plugin/lib/zzzot.jar.pack" />
|
||||
<delete file="plugin/eepsite/webapps/tracker.war.pack" />
|
||||
<delete file="plugin/LICENSE.txt" />
|
||||
<delete file="plugin/README.txt" />
|
||||
<delete file="zzzot.xpi2p" />
|
||||
<delete file="zzzot-update.xpi2p" />
|
||||
<delete file="zzzot.su3" />
|
||||
<delete file="zzzot-update.su3" />
|
||||
<delete file="plugin.zip" />
|
||||
<delete dir="plugin/eepsite/docroot/torrents/" />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
@ -2,7 +2,7 @@ clientApp.0.main=net.i2p.zzzot.ZzzOTController
|
||||
clientApp.0.name=ZzzOT
|
||||
clientApp.0.args=-d $PLUGIN start
|
||||
clientApp.0.stopargs=-d $PLUGIN stop
|
||||
clientApp.0.delay=15
|
||||
clientApp.0.delay=40
|
||||
clientApp.0.startOnLoad=true
|
||||
# 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
|
||||
|
@ -1,18 +1,22 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!--
|
||||
Configure a custom context for the eepsite.
|
||||
|
||||
This context contains only a Context with a default servlet
|
||||
This context contains only a ServletContextHandler with a default servlet
|
||||
to serve static html files and images.
|
||||
-->
|
||||
|
||||
<Configure class="org.mortbay.jetty.servlet.Context">
|
||||
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="resourceBase">$PLUGIN/eepsite/docroot/</Set>
|
||||
<Call name="setInitParameter">
|
||||
<Arg>cacheControl</Arg>
|
||||
<Arg>max-age=3600,public</Arg>
|
||||
</Call>
|
||||
<Call name="addServlet">
|
||||
<Arg>org.mortbay.jetty.servlet.DefaultServlet</Arg>
|
||||
<Arg>org.eclipse.jetty.servlet.DefaultServlet</Arg>
|
||||
<Arg>/</Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!--
|
||||
Configure a custom context for the eepsite.
|
||||
@ -22,21 +22,15 @@ Configure a custom context for the eepsite.
|
||||
* parameter value.
|
||||
-->
|
||||
|
||||
<Configure class="org.mortbay.jetty.servlet.Context">
|
||||
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
|
||||
<Set name="contextPath">/cgi-bin</Set>
|
||||
<Set name="resourceBase">$PLUGIN/eepsite/cgi-bin/</Set>
|
||||
<Call name="setInitParams">
|
||||
<Arg>
|
||||
<Map>
|
||||
<Entry>
|
||||
<Item>Path</Item>
|
||||
<Item>/usr/local/bin:/bin:/usr/bin</Item>
|
||||
</Entry>
|
||||
</Map>
|
||||
</Arg>
|
||||
<Call name="setInitParameter">
|
||||
<Arg>Path</Arg>
|
||||
<Arg>/usr/local/bin:/bin:/usr/bin</Arg>
|
||||
</Call>
|
||||
<Call name="addServlet">
|
||||
<Arg>org.mortbay.servlet.CGI</Arg>
|
||||
<Arg>org.eclipse.jetty.servlets.CGI</Arg>
|
||||
<Arg>/</Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
|
@ -35,23 +35,23 @@
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<context-param>
|
||||
<param-name>org.mortbay.jetty.servlet.SessionDomain</param-name>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
|
||||
<param-value>127.0.0.1</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.mortbay.jetty.servlet.SessionPath</param-name>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
|
||||
<param-value>/</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.mortbay.jetty.servlet.MaxAge</param-name>
|
||||
<param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
|
||||
<param-value>-1</param-value>
|
||||
</context-param>
|
||||
-->
|
||||
|
||||
<context-param>
|
||||
<param-name>org.mortbay.jetty.webapp.NoTLDJarPattern</param-name>
|
||||
<param-name>org.eclipse.jetty.webapp.NoTLDJarPattern</param-name>
|
||||
<param-value>start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar</param-value>
|
||||
</context-param>
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<servlet>
|
||||
<servlet-name>default</servlet-name>
|
||||
<servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
|
||||
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>acceptRanges</param-name>
|
||||
<param-value>true</param-value>
|
||||
@ -153,12 +153,10 @@
|
||||
<param-name>useFileMappedBuffer</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<!--
|
||||
<init-param>
|
||||
<param-name>cacheControl</param-name>
|
||||
<param-value>max-age=3600,public</param-value>
|
||||
</init-param>
|
||||
-->
|
||||
<load-on-startup>0</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
@ -308,7 +306,7 @@
|
||||
<!-- Uncomment for dynamic invocation
|
||||
<servlet>
|
||||
<servlet-name>invoker</servlet-name>
|
||||
<servlet-class>org.mortbay.jetty.servlet.Invoker</servlet-class>
|
||||
<servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
|
||||
<init-param>
|
||||
<param-name>verbose</param-name>
|
||||
<param-value>false</param-value>
|
||||
|
@ -10,6 +10,9 @@ This link is also at the top of your router console when ZzzOT is running.
|
||||
<p>Report bugs or add comments on
|
||||
<a href="http://zzz.i2p//forums/16">the plugin forum on zzz.i2p</a>.
|
||||
|
||||
<p><b>This help file is $PLUGIN/eepsite/docroot/help.html, you should probably move it
|
||||
outside of the document root before you announce your eepsite as it may contain your user name.</b>
|
||||
|
||||
<h3>Eepsite Key and Helpful Hints for I2P</h3>
|
||||
|
||||
<p>Your Base 32 address is <a href="http://$B32/">$B32</a>.
|
||||
@ -47,8 +50,6 @@ This link is also at the top of your router console when ZzzOT is running.
|
||||
If your tracker gets over 1000 peers, you will probably want to increase the number of tunnels.
|
||||
<p>The Jetty webserver port is 7662. If you must change it, edit jetty.xml, i2ptunnel.config, and plugins.config
|
||||
in the directory $PLUGIN. Then stop and restart the plugin.
|
||||
<p>This help file is $PLUGIN/eepsite/docroot/help.html, you should probably move it
|
||||
outside of the document root before you announce your eepsite as it may contain your user name.
|
||||
<p>As you probably know, an open tracker does not require torrents to be registered,
|
||||
and it does not host torrent files. You can, however, host torrent files elsewhere on
|
||||
the eepsite, for example at <a href="http://$B32/torrents/">/torrents</a>.
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!-- ========================================================================= -->
|
||||
<!-- This file configures the Jetty server. -->
|
||||
@ -9,20 +9,20 @@
|
||||
<!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section -->
|
||||
<!-- to access the server directly (bypassing i2p) -->
|
||||
<!-- from other computers. -->
|
||||
<!-- * port: Default 7662 in the addConnector section -->
|
||||
<!-- * docroot: Change the ResourceBase in the addContext section -->
|
||||
<!-- * port: Default 7662 in the addConnector section -->
|
||||
<!-- * docroot: Change the ResourceBase in the contexts/base-context.xml file -->
|
||||
<!-- to serve files from a different location. -->
|
||||
<!-- * threads: Raise MinThreads and/or MaxThreads in the addListener section -->
|
||||
<!-- * threads: Raise maximumPoolSize in the ThreadPool section -->
|
||||
<!-- if you have a high-traffic site and get a lot of warnings. -->
|
||||
<!-- -->
|
||||
<!-- I2P uses Jetty 6.1.26. If you need web server features not found -->
|
||||
<!-- in Jetty 6, you may install and run Jetty 7 or 8 in a different JVM -->
|
||||
<!-- I2P uses Jetty 9. If you need web server features not found -->
|
||||
<!-- 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 -->
|
||||
<!-- 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 . -->
|
||||
<!-- -->
|
||||
<!-- Jetty now uses the I2P logging system rather than wrapper.log. -->
|
||||
<!-- Use the log override org.mortbay.jetty.Server to adjust the log level. -->
|
||||
<!-- Use the log override org.eclipse.jetty.server.Server to adjust the log level. -->
|
||||
<!-- -->
|
||||
<!-- Note that the XML encoding for this file is UTF-8. -->
|
||||
<!-- -->
|
||||
@ -37,40 +37,35 @@
|
||||
<!-- =============================================================== -->
|
||||
|
||||
|
||||
<Configure id="Server" class="org.mortbay.jetty.Server">
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Server Thread Pool -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="ThreadPool">
|
||||
<Arg>
|
||||
|
||||
<!-- PICK ONE -->
|
||||
|
||||
<!-- If you don't have or want threadpool
|
||||
Requests above the max will be queued
|
||||
<!--
|
||||
Requests above the maxThreads + queue_size will be rejected and logged.
|
||||
ref:
|
||||
https://wiki.eclipse.org/Jetty/Howto/High_Load
|
||||
http://trac.i2p2.i2p/ticket/1395
|
||||
-->
|
||||
<!--
|
||||
<New class="org.mortbay.thread.QueuedThreadPool">
|
||||
<Set name="minThreads">1</Set>
|
||||
<Set name="maxThreads">16</Set>
|
||||
<Set name="lowThreads">2</Set>
|
||||
<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>
|
||||
<New class="java.util.concurrent.LinkedBlockingQueue">
|
||||
<Arg type="int">50</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Set name="minThreads">4</Set>
|
||||
<Set name="maxThreads">20</Set>
|
||||
<Set name="idleTimeout">60000</Set>
|
||||
<Set name="daemon">true</Set>
|
||||
<Set name="name">Zzzot Jetty</Set>
|
||||
</New>
|
||||
-->
|
||||
|
||||
<!-- Optional Java 5 bounded threadpool with job queue
|
||||
Requests above the max will be rejected
|
||||
TODO: would be nice to use the 5-arg constructor but
|
||||
how do you use an Enum as the TimeUnit argument?
|
||||
Alternatively, make a custom class where we can
|
||||
set the thread name, set daemon, etc.
|
||||
See RouterConsoleRunner.
|
||||
-->
|
||||
<New class="org.mortbay.thread.concurrent.ThreadPool">
|
||||
<Arg type="int">0</Arg>
|
||||
<Set name="corePoolSize">1</Set>
|
||||
<Set name="maximumPoolSize">16</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Arg>
|
||||
|
||||
|
||||
|
||||
@ -82,18 +77,34 @@
|
||||
|
||||
<!-- Use this connector for many frequently idle connections
|
||||
and for threadless continuations.
|
||||
Not recommended on Java 5 - comment this out, and uncomment the
|
||||
SocketConnector below.
|
||||
Do not use for gij or JamVM - comment this out, and uncomment the
|
||||
SocketConnector below.
|
||||
-->
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.mortbay.jetty.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="port">7662</Set>
|
||||
<Set name="maxIdleTime">60000</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="idleTimeout">600000</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
@ -103,7 +114,7 @@
|
||||
<!-- =========================================================== -->
|
||||
<!--
|
||||
<Set name="sessionIdManager">
|
||||
<New class="org.mortbay.jetty.servlet.HashSessionIdManager">
|
||||
<New class="org.eclipse.jetty.server.session.HashSessionIdManager">
|
||||
<Set name="workerName">node1</Set>
|
||||
</New>
|
||||
</Set>
|
||||
@ -118,74 +129,74 @@
|
||||
<!-- that is hosted on the same eepsite. -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="handler">
|
||||
<New id="Rewrite" class="org.mortbay.jetty.handler.rewrite.RewriteHandler">
|
||||
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
||||
<Set name="rewriteRequestURI">true</Set>
|
||||
<Set name="rewritePathInfo">false</Set>
|
||||
<Set name="originalPathAttribute">requestedPath</Set>
|
||||
<Set name="rules">
|
||||
<Array type="org.mortbay.jetty.handler.rewrite.Rule">
|
||||
<Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/a</Set>
|
||||
<Set name="replacement">/tracker/announce.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/announce</Set>
|
||||
<Set name="replacement">/tracker/announce.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/announce.jsp</Set>
|
||||
<Set name="replacement">/tracker/announce.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/announce.php</Set>
|
||||
<Set name="replacement">/tracker/announce.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/scrape</Set>
|
||||
<Set name="replacement">/tracker/scrape.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/scrape.jsp</Set>
|
||||
<Set name="replacement">/tracker/scrape.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/scrape.php</Set>
|
||||
<Set name="replacement">/tracker/scrape.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/Seedless</Set>
|
||||
<Set name="replacement">/tracker/seedless.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/Seedless/</Set>
|
||||
<Set name="replacement">/tracker/seedless.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/Seedless/index.jsp</Set>
|
||||
<Set name="replacement">/tracker/seedless.jsp</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule">
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/Seedless/seedless</Set>
|
||||
<Set name="replacement">/tracker/seedless.jsp</Set>
|
||||
</New>
|
||||
@ -193,17 +204,17 @@
|
||||
</Array>
|
||||
</Set>
|
||||
<Set name="handler">
|
||||
<New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
|
||||
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
|
||||
<Set name="handlers">
|
||||
<Array type="org.mortbay.jetty.Handler">
|
||||
<Array type="org.eclipse.jetty.server.Handler">
|
||||
<Item>
|
||||
<New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
|
||||
<New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
|
||||
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>
|
||||
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
|
||||
</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
@ -211,7 +222,32 @@
|
||||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Create the deployment manager -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- The deplyment manager handles the lifecycle of deploying web -->
|
||||
<!-- applications. Apps are provided by instances of the -->
|
||||
<!-- AppProvider interface. Typically these are provided by -->
|
||||
<!-- one or more of: -->
|
||||
<!-- jetty-webapps.xml - monitors webapps for wars and dirs -->
|
||||
<!-- jetty-contexts.xml - monitors contexts for context xml -->
|
||||
<!-- jetty-templates.xml - monitors contexts and templates -->
|
||||
<!-- =============================================================== -->
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
|
||||
<Set name="contexts">
|
||||
<Ref id="Contexts" />
|
||||
</Set>
|
||||
<Call name="setContextAttribute">
|
||||
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
|
||||
<Arg>.*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Configure the context deployer -->
|
||||
<!-- A context deployer will deploy contexts described in -->
|
||||
@ -223,15 +259,16 @@
|
||||
<!-- in the $JETTY_HOME/contexts directory -->
|
||||
<!-- -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addLifeCycle">
|
||||
<Arg>
|
||||
<New class="org.mortbay.jetty.deployer.ContextDeployer">
|
||||
<Set name="contexts"><Ref id="Contexts"/></Set>
|
||||
<Set name="configurationDir">$PLUGIN/contexts</Set>
|
||||
<Set name="scanInterval">0</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Ref id="DeploymentManager">
|
||||
<Call name="addAppProvider">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<Set name="monitoredDirName">$PLUGIN/contexts</Set>
|
||||
<Set name="scanInterval">120</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Configure the webapp deployer. -->
|
||||
@ -246,18 +283,18 @@
|
||||
<!-- Normally only one type of deployer need be used. -->
|
||||
<!-- -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addLifeCycle">
|
||||
<Arg>
|
||||
<New class="org.mortbay.jetty.deployer.WebAppDeployer">
|
||||
<Set name="contexts"><Ref id="Contexts"/></Set>
|
||||
<Set name="webAppDir">$PLUGIN/eepsite/webapps</Set>
|
||||
<Set name="parentLoaderPriority">false</Set>
|
||||
<Set name="extract">true</Set>
|
||||
<Set name="allowDuplicates">false</Set>
|
||||
<Set name="defaultsDescriptor">$PLUGIN/etc/webdefault.xml</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Ref id="DeploymentManager">
|
||||
<Call id="webappprovider" name="addAppProvider">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<Set name="monitoredDirName">$PLUGIN/eepsite/webapps</Set>
|
||||
<Set name="parentLoaderPriority">false</Set>
|
||||
<Set name="extractWars">false</Set>
|
||||
<Set name="defaultsDescriptor">$PLUGIN/etc/webdefault.xml</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Configure Authentication Realms -->
|
||||
@ -268,9 +305,9 @@
|
||||
<!-- =========================================================== -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<Set name="UserRealms">
|
||||
<Array type="org.mortbay.jetty.security.UserRealm">
|
||||
<Array type="org.eclipse.jetty.security.LoginService">
|
||||
<Item>
|
||||
<New class="org.mortbay.jetty.security.HashUserRealm">
|
||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||
<Set name="name">Test Realm</Set>
|
||||
<Set name="config">$PLUGIN/etc/realm.properties</Set>
|
||||
<Set name="refreshInterval">0</Set>
|
||||
@ -305,8 +342,6 @@
|
||||
<!-- extra options -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="stopAtShutdown">true</Set>
|
||||
<Set name="sendServerVersion">false</Set>
|
||||
<Set name="sendDateHeader">true</Set>
|
||||
<Set name="gracefulShutdown">1000</Set>
|
||||
<Set name="stopTimeout">1000</Set>
|
||||
|
||||
</Configure>
|
||||
|
@ -2,27 +2,29 @@ tunnel.0.description=ZzzOT
|
||||
tunnel.0.i2cpHost=127.0.0.1
|
||||
tunnel.0.i2cpPort=7654
|
||||
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.encryptLeaseSet=false
|
||||
tunnel.0.option.i2cp.reduceIdleTime=1200000
|
||||
tunnel.0.option.i2cp.reduceOnIdle=true
|
||||
tunnel.0.option.i2cp.reduceQuantity=1
|
||||
tunnel.0.option.i2p.streaming.connectDelay=0
|
||||
tunnel.0.option.i2p.streaming.maxConcurrentStreams=40
|
||||
tunnel.0.option.i2p.streaming.maxConnsPerHour=100
|
||||
tunnel.0.option.i2p.streaming.maxConnsPerMinute=10
|
||||
tunnel.0.option.i2p.streaming.maxTotalConnsPerHour=2500
|
||||
tunnel.0.option.i2p.streaming.maxTotalConnsPerMinute=60
|
||||
tunnel.0.option.i2p.streaming.maxConcurrentStreams=80
|
||||
tunnel.0.option.i2p.streaming.maxConnsPerHour=300
|
||||
tunnel.0.option.i2p.streaming.maxConnsPerMinute=20
|
||||
tunnel.0.option.i2p.streaming.maxTotalConnsPerHour=50000
|
||||
tunnel.0.option.i2p.streaming.maxTotalConnsPerMinute=2000
|
||||
tunnel.0.option.inbound.backupQuantity=0
|
||||
tunnel.0.option.inbound.length=3
|
||||
tunnel.0.option.inbound.lengthVariance=0
|
||||
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.length=3
|
||||
tunnel.0.option.outbound.lengthVariance=0
|
||||
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.startOnLoad=true
|
||||
tunnel.0.targetHost=127.0.0.1
|
||||
|
@ -5,11 +5,16 @@
|
||||
# usage: makeplugin.sh plugindir
|
||||
#
|
||||
# zzz 2010-02
|
||||
# zzz 2014-08 added support for su3 files
|
||||
#
|
||||
PUBKEYDIR=$HOME/.i2p-plugin-keys
|
||||
PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key
|
||||
PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key
|
||||
B64KEYFILE=$PUBKEYDIR/plugin-public-signing.txt
|
||||
PUBKEYSTORE=$PUBKEYDIR/plugin-su3-public-signing.crt
|
||||
PRIVKEYSTORE=$PUBKEYDIR/plugin-su3-keystore.ks
|
||||
KEYTYPE=RSA_SHA512_4096
|
||||
|
||||
export I2P=../i2p/pkg-temp
|
||||
|
||||
PLUGINDIR=${1:-plugin}
|
||||
@ -17,46 +22,67 @@ PLUGINDIR=${1:-plugin}
|
||||
PC=plugin.config
|
||||
PCT=${PC}.tmp
|
||||
|
||||
if [ ! -f $PRIVKEYFILE ]
|
||||
then
|
||||
mkdir -p $PUBKEYDIR
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate keygen $PUBKEYFILE $PRIVKEYFILE || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.data.Base64 encode $PUBKEYFILE $B64KEYFILE || exit 1
|
||||
rm -rf logs/
|
||||
chmod 444 $PUBKEYFILE $B64KEYFILE
|
||||
chmod 400 $PRIVKEYFILE
|
||||
echo "Created new keys: $PUBKEYFILE $PRIVKEYFILE"
|
||||
fi
|
||||
|
||||
rm -f plugin.zip
|
||||
if [ ! -d $PLUGINDIR ]
|
||||
then
|
||||
echo "You must have a $PLUGINDIR directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OPWD=$PWD
|
||||
cd $PLUGINDIR
|
||||
|
||||
if [ ! -f $PC ]
|
||||
if [ ! -f $PLUGINDIR/$PC ]
|
||||
then
|
||||
echo "You must have a $PC file"
|
||||
echo "You must have a $PLUGINDIR/$PC file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q '^signer=' $PC
|
||||
SIGNER=`grep '^signer=' $PLUGINDIR/$PC`
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a signer in $PC"
|
||||
echo 'For example signer=joe@mail.i2p'
|
||||
echo "You must have a plugin name in $PC"
|
||||
echo 'For example name=foo'
|
||||
exit 1
|
||||
fi
|
||||
SIGNER=`echo $SIGNER | cut -f 2 -d '='`
|
||||
|
||||
if [ ! -f $PRIVKEYFILE ]
|
||||
then
|
||||
echo "Creating new XPI2P DSA keys"
|
||||
mkdir -p $PUBKEYDIR || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate keygen $PUBKEYFILE $PRIVKEYFILE || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.data.Base64 encode $PUBKEYFILE $B64KEYFILE || exit 1
|
||||
rm -rf logs/
|
||||
chmod 444 $PUBKEYFILE $B64KEYFILE
|
||||
chmod 400 $PRIVKEYFILE
|
||||
echo "Created new XPI2P keys: $PUBKEYFILE $PRIVKEYFILE"
|
||||
fi
|
||||
|
||||
if [ ! -f $PRIVKEYSTORE ]
|
||||
then
|
||||
echo "Creating new SU3 $KEYTYPE keys for $SIGNER"
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File keygen -t $KEYTYPE $PUBKEYSTORE $PRIVKEYSTORE $SIGNER || exit 1
|
||||
echo '*** Save your password in a safe place!!! ***'
|
||||
rm -rf logs/
|
||||
# copy to the router dir so verify will work
|
||||
CDIR=$I2P/certificates/plugin
|
||||
mkdir -p $CDIR || exit 1
|
||||
CFILE=$CDIR/`echo $SIGNER | sed s/@/_at_/`.crt
|
||||
cp $PUBKEYSTORE $CFILE
|
||||
chmod 444 $PUBKEYSTORE
|
||||
chmod 400 $PRIVKEYSTORE
|
||||
chmod 644 $CFILE
|
||||
echo "Created new SU3 keys: $PUBKEYSTORE $PRIVKEYSTORE"
|
||||
echo "Copied public key to $CFILE for testing"
|
||||
fi
|
||||
|
||||
rm -f plugin.zip
|
||||
|
||||
OPWD=$PWD
|
||||
cd $PLUGINDIR
|
||||
|
||||
grep -q '^name=' $PC
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a plugin name in $PC"
|
||||
echo 'For example name=foo'
|
||||
echo 'For example name=foo'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -64,7 +90,7 @@ grep -q '^version=' $PC
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a version in $PC"
|
||||
echo 'For example version=0.1.2'
|
||||
echo 'For example version=0.1.2'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -72,33 +98,41 @@ fi
|
||||
grep -v '^date=' $PC > $PCT
|
||||
DATE=`date '+%s000'`
|
||||
echo "date=$DATE" >> $PCT
|
||||
mv $PCT $PC
|
||||
mv $PCT $PC || exit 1
|
||||
|
||||
# add our Base64 key
|
||||
grep -v '^key=' $PC > $PCT
|
||||
B64KEY=`cat $B64KEYFILE`
|
||||
echo "key=$B64KEY" >> $PCT || exit 1
|
||||
mv $PCT $PC
|
||||
mv $PCT $PC || exit 1
|
||||
|
||||
# zip it
|
||||
zip -r $OPWD/plugin.zip * -x \*.jar || exit 1
|
||||
zip -r $OPWD/plugin.zip * || exit 1
|
||||
|
||||
# get the version and use it for the sud header
|
||||
VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
|
||||
# get the name and use it for the file name
|
||||
NAME=`grep '^name=' $PC | cut -f 2 -d '='`
|
||||
XPI2P=${NAME}.xpi2p
|
||||
SU3=${NAME}.su3
|
||||
cd $OPWD
|
||||
|
||||
# sign it
|
||||
echo 'Signing. ...'
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign plugin.zip $XPI2P $PRIVKEYFILE $VERSION || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File sign -c PLUGIN -t $KEYTYPE plugin.zip $SU3 $PRIVKEYSTORE $VERSION $SIGNER || exit 1
|
||||
rm -f plugin.zip
|
||||
|
||||
# verify
|
||||
echo 'Verifying. ...'
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion $XPI2P || exit 1
|
||||
java -cp $I2P/lib/i2p.jar -Drouter.trustedUpdateKeys=$B64KEY net.i2p.crypto.TrustedUpdate verifysig $XPI2P || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File showversion $SU3 || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File verifysig -k $PUBKEYSTORE $SU3 || exit 1
|
||||
rm -rf logs/
|
||||
|
||||
echo -n 'Plugin created: '
|
||||
echo 'Plugin files created: '
|
||||
wc -c $XPI2P
|
||||
wc -c $SU3
|
||||
|
||||
exit 0
|
||||
|
@ -5,6 +5,8 @@ consoleLinkURL=http://127.0.0.1:7662/tracker/index.jsp
|
||||
description=Open tracker
|
||||
author=zzz
|
||||
updateURL=http://stats.i2p/i2p/plugins/zzzot-update.xpi2p
|
||||
updateURL.su3=http://stats.i2p/i2p/plugins/zzzot-update.su3
|
||||
websiteURL=http://zzz.i2p/forums/16
|
||||
license=Apache 2.0
|
||||
min-jetty-version=6
|
||||
min-jetty-version=9
|
||||
min-i2p-version=0.9.29
|
||||
|
3
scripts/zzzot.config
Normal file
3
scripts/zzzot.config
Normal file
@ -0,0 +1,3 @@
|
||||
# announce interval in seconds
|
||||
# minimum 900 (15 minutes), maximum 21600 (6 hours)
|
||||
interval=1620
|
@ -11,10 +11,10 @@
|
||||
<pathelement location="${i2plib}/mstreaming.jar" />
|
||||
<pathelement location="${ant.home}/lib/ant.jar"/>
|
||||
<pathelement location="${jettylib}/org.mortbay.jetty.jar"/>
|
||||
<pathelement location="${jettylib}/jasper-compiler.jar" />
|
||||
<pathelement location="${jettylib}/jasper-runtime.jar" />
|
||||
<pathelement location="${jettylib}/javax.servlet.jar" />
|
||||
<pathelement location="${jettylib}/jetty-util.jar" />
|
||||
<pathelement location="${jettylib}/jetty-xml.jar" />
|
||||
<pathelement location="${jettylib}/commons-logging.jar" />
|
||||
<pathelement location="${jettylib}/commons-el.jar" />
|
||||
</path>
|
||||
@ -25,16 +25,17 @@
|
||||
</target>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.7" />
|
||||
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
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"
|
||||
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" >
|
||||
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" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
@ -66,13 +67,15 @@
|
||||
<javac
|
||||
debug="true"
|
||||
deprecation="on"
|
||||
source="1.5" target="1.5"
|
||||
source="${javac.version}" target="${javac.version}"
|
||||
destdir="build/war/WEB-INF/classes"
|
||||
srcdir="./build/jspjava"
|
||||
includes="**/*.java"
|
||||
includeAntRuntime="false"
|
||||
classpathref="jspcp"
|
||||
failonerror="true" />
|
||||
failonerror="true" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
|
||||
<copy file="jsp/WEB-INF/web.xml" tofile="build/web.xml" />
|
||||
<loadfile property="jspc.web.fragment" srcfile="build/web-fragment.xml" />
|
||||
|
@ -16,22 +16,20 @@ package net.i2p.zzzot;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* A 20-byte SHA1 info hash
|
||||
*/
|
||||
public class InfoHash extends ByteArray {
|
||||
public class InfoHash extends SimpleDataStructure {
|
||||
|
||||
public InfoHash(String data) throws UnsupportedEncodingException {
|
||||
this(data.getBytes("ISO-8859-1"));
|
||||
}
|
||||
public static final int LENGTH = 20;
|
||||
|
||||
public InfoHash(byte[] data) {
|
||||
super(data);
|
||||
if (data.length != 20)
|
||||
throw new IllegalArgumentException("Bad infohash length: " + data.length);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return LENGTH;
|
||||
}
|
||||
}
|
||||
|
@ -16,22 +16,20 @@ package net.i2p.zzzot;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* A 20-byte peer ID
|
||||
*/
|
||||
public class PID extends ByteArray {
|
||||
public class PID extends SimpleDataStructure {
|
||||
|
||||
public PID(String data) throws UnsupportedEncodingException {
|
||||
this(data.getBytes("ISO-8859-1"));
|
||||
}
|
||||
public static final int LENGTH = 20;
|
||||
|
||||
public PID(byte[] data) {
|
||||
super(data);
|
||||
if (data.length != 20)
|
||||
throw new IllegalArgumentException("Bad peer ID length: " + data.length);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return LENGTH;
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,12 @@ package net.i2p.zzzot;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
/*
|
||||
* A single peer for a single torrent.
|
||||
@ -38,15 +36,9 @@ public class Peer extends HashMap<String, Object> {
|
||||
|
||||
private long lastSeen;
|
||||
private long bytesLeft;
|
||||
private static final ConcurrentHashMap<String, String> destCache = new ConcurrentHashMap();
|
||||
private static final Integer PORT = Integer.valueOf(6881);
|
||||
private static final long CLEAN_TIME = 3*60*60*1000;
|
||||
|
||||
static {
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
|
||||
}
|
||||
|
||||
public Peer(byte[] id, Destination address) {
|
||||
public Peer(byte[] id, Destination address, ConcurrentMap<String, String> destCache) {
|
||||
super(3);
|
||||
if (id.length != 20)
|
||||
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");
|
||||
} catch (UnsupportedEncodingException uee) { return null; }
|
||||
}
|
||||
|
||||
private static class Cleaner implements SimpleTimer.TimedEvent {
|
||||
public void timeReached() {
|
||||
destCache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
225
src/java/net/i2p/zzzot/RandomIterator.java
Normal file
225
src/java/net/i2p/zzzot/RandomIterator.java
Normal 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…</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!");
|
||||
}
|
||||
}
|
@ -18,13 +18,30 @@ package net.i2p.zzzot;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SDSCache;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
|
||||
/**
|
||||
* All the torrents
|
||||
*/
|
||||
public class Torrents extends ConcurrentHashMap<InfoHash, Peers> {
|
||||
|
||||
public Torrents() {
|
||||
private static final int CACHE_SIZE = 2048;
|
||||
private final SDSCache<InfoHash> _hashCache;
|
||||
private final SDSCache<PID> _pidCache;
|
||||
private final Integer _interval;
|
||||
|
||||
/**
|
||||
* @param interval in seconds
|
||||
*/
|
||||
public Torrents(int interval) {
|
||||
super();
|
||||
_hashCache = new SDSCache<InfoHash>(InfoHash.class, InfoHash.LENGTH, CACHE_SIZE);
|
||||
_pidCache = new SDSCache<PID>(PID.class, PID.LENGTH, CACHE_SIZE);
|
||||
_interval = Integer.valueOf(interval);
|
||||
}
|
||||
|
||||
public int countPeers() {
|
||||
@ -34,4 +51,60 @@ public class Torrents extends ConcurrentHashMap<InfoHash, Peers> {
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return in seconds
|
||||
* @since 0.12.0
|
||||
*/
|
||||
public Integer getInterval() {
|
||||
return _interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
*
|
||||
* @throws IllegalArgumentException if data is not the correct number of bytes
|
||||
* @since 0.12.0
|
||||
*/
|
||||
public InfoHash createInfoHash(String data) throws IllegalArgumentException {
|
||||
byte[] d = DataHelper.getASCII(data);
|
||||
if (d.length != InfoHash.LENGTH)
|
||||
throw new IllegalArgumentException("bad infohash length " + d.length);
|
||||
return _hashCache.get(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
*
|
||||
* @throws IllegalArgumentException if data is not the correct number of bytes
|
||||
* @since 0.12.0
|
||||
*/
|
||||
public PID createPID(String data) throws IllegalArgumentException {
|
||||
byte[] d = DataHelper.getASCII(data);
|
||||
if (d.length != PID.LENGTH)
|
||||
throw new IllegalArgumentException("bad peer id length " + d.length);
|
||||
return _pidCache.get(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.12.0
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
clearCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.12.0
|
||||
*/
|
||||
private void clearCaches() {
|
||||
// not available until 0.9.17
|
||||
if (VersionComparator.comp(CoreVersion.VERSION, "0.9.17") >= 0) {
|
||||
try {
|
||||
_hashCache.clear();
|
||||
_pidCache.clear();
|
||||
} catch (Throwable t) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,34 +17,74 @@ package net.i2p.zzzot;
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* Instantiate this to fire it up
|
||||
*/
|
||||
class ZzzOT {
|
||||
|
||||
private Torrents _torrents;
|
||||
private static final long CLEAN_TIME = 4*60*1000;
|
||||
private static final long EXPIRE_TIME = 60*60*1000;
|
||||
private final Torrents _torrents;
|
||||
private final Cleaner _cleaner;
|
||||
private final ConcurrentHashMap<String, String> _destCache = new ConcurrentHashMap<String, String>();
|
||||
private final long EXPIRE_TIME;
|
||||
|
||||
ZzzOT() {
|
||||
_torrents = new Torrents();
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
|
||||
private static final String PROP_INTERVAL = "interval";
|
||||
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 MIN_INTERVAL = 15*60;
|
||||
private static final int MAX_INTERVAL = 6*60*60;
|
||||
|
||||
ZzzOT(I2PAppContext ctx, Properties p) {
|
||||
String intv = p.getProperty(PROP_INTERVAL);
|
||||
int interval = DEFAULT_INTERVAL;
|
||||
if (intv != null) {
|
||||
try {
|
||||
interval = Integer.parseInt(intv);
|
||||
if (interval < MIN_INTERVAL)
|
||||
interval = MIN_INTERVAL;
|
||||
else if (interval > MAX_INTERVAL)
|
||||
interval = MAX_INTERVAL;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
_torrents = new Torrents(interval);
|
||||
EXPIRE_TIME = 1000 * (interval + interval / 2);
|
||||
_cleaner = new Cleaner(ctx);
|
||||
}
|
||||
|
||||
Torrents getTorrents() {
|
||||
return _torrents;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_torrents.clear();
|
||||
// no way to stop the cleaner
|
||||
/** @since 0.9.14 */
|
||||
ConcurrentHashMap<String, String> getDestCache() {
|
||||
return _destCache;
|
||||
}
|
||||
|
||||
private class Cleaner implements SimpleTimer.TimedEvent {
|
||||
void start() {
|
||||
_cleaner.forceReschedule(CLEAN_TIME);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_cleaner.cancel();
|
||||
_torrents.clear();
|
||||
_destCache.clear();
|
||||
}
|
||||
|
||||
private class Cleaner extends SimpleTimer2.TimedEvent {
|
||||
|
||||
private final AtomicInteger _runCount = new AtomicInteger();
|
||||
|
||||
/** must schedule later */
|
||||
public Cleaner(I2PAppContext ctx) {
|
||||
super(ctx.simpleTimer2());
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
long now = System.currentTimeMillis();
|
||||
@ -61,6 +101,10 @@ class ZzzOT {
|
||||
if (recent <= 0)
|
||||
iter.remove();
|
||||
}
|
||||
if (_runCount.incrementAndGet() % (DEST_CACHE_CLEAN_TIME / CLEAN_TIME) == 0) {
|
||||
_destCache.clear();
|
||||
}
|
||||
schedule(CLEAN_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,20 +21,28 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.xml.XmlConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
/**
|
||||
* This handles the starting and stopping of an eepsite tunnel and jetty
|
||||
@ -47,39 +55,93 @@ import org.mortbay.xml.XmlConfiguration;
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class ZzzOTController {
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ZzzOTController.class);
|
||||
private static Server _server;
|
||||
private static TunnelController _tunnel;
|
||||
private static ZzzOT _zzzot;
|
||||
private static Object _lock = new Object();
|
||||
public class ZzzOTController implements ClientApp {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private final String[] _args;
|
||||
private final ClientAppManager _mgr;
|
||||
private Server _server;
|
||||
private TunnelController _tunnel;
|
||||
private final ZzzOT _zzzot;
|
||||
/** only for main() */
|
||||
private static volatile ZzzOTController _controller;
|
||||
|
||||
private static final String BACKUP = "jetty5.xml";
|
||||
private ClientAppState _state = UNINITIALIZED;
|
||||
|
||||
private static final String NAME = "ZzzOT";
|
||||
private static final String CONFIG_FILE = "zzzot.config";
|
||||
private static final String BACKUP_SUFFIX = ".jetty8";
|
||||
private static final String[] xmlFiles = {
|
||||
"jetty.xml", "contexts/base-context.xml", "contexts/cgi-context.xml",
|
||||
"etc/realm.properties", "etc/webdefault.xml" };
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length != 3 || (!"-d".equals(args[0])))
|
||||
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]");
|
||||
if ("start".equals(args[2]))
|
||||
start(args);
|
||||
else if ("stop".equals(args[2]))
|
||||
stop();
|
||||
else
|
||||
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]");
|
||||
}
|
||||
|
||||
public static Torrents getTorrents() {
|
||||
synchronized(_lock) {
|
||||
if (_zzzot == null)
|
||||
_zzzot = new ZzzOT();
|
||||
/**
|
||||
* @since 0.12.0
|
||||
*/
|
||||
public ZzzOTController(I2PAppContext ctx, ClientAppManager mgr, String args[]) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(ZzzOTController.class);
|
||||
_mgr = mgr;
|
||||
_args = args;
|
||||
File cfile = new File(_context.getAppDir(), "plugins/zzzot/" + CONFIG_FILE);
|
||||
Properties props = new Properties();
|
||||
if (cfile.exists()) {
|
||||
try {
|
||||
DataHelper.loadProps(props, cfile);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Failed loading zzzot config from " + cfile, ioe);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("No config file " + cfile);
|
||||
}
|
||||
return _zzzot.getTorrents();
|
||||
_zzzot = new ZzzOT(ctx, props);
|
||||
_state = INITIALIZED;
|
||||
}
|
||||
|
||||
private static void start(String args[]) {
|
||||
File pluginDir = new File(args[1]);
|
||||
/**
|
||||
* No longer supported, as we now need the ClientAppManager for the webapp to find us
|
||||
*/
|
||||
public synchronized static void main(String args[]) {
|
||||
throw new UnsupportedOperationException("Must use ClientApp interface");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if not running
|
||||
*/
|
||||
public static Torrents getTorrents() {
|
||||
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.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
|
||||
*/
|
||||
private void start(String args[]) {
|
||||
//File pluginDir = new File(args[1]);
|
||||
File pluginDir = new File(_context.getAppDir(), "plugins/zzzot");
|
||||
if (!pluginDir.exists())
|
||||
throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist");
|
||||
|
||||
@ -96,20 +158,21 @@ public class ZzzOTController {
|
||||
_log.error("Unable to create " + key.getAbsolutePath() + ' ' + e);
|
||||
throw new IllegalArgumentException("Unable to create " + key.getAbsolutePath() + ' ' + e);
|
||||
}
|
||||
_log.error("NOTICE: ZzzOT: New eepsite keys created in " + key.getAbsolutePath());
|
||||
_log.error("NOTICE: ZzzOT: You should back up this file!");
|
||||
_log.logAlways(Log.INFO, "NOTICE: ZzzOT: New eepsite keys created in " + key.getAbsolutePath());
|
||||
_log.logAlways(Log.INFO, "NOTICE: ZzzOT: You should back up this file!");
|
||||
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||
String b64 = dest.toBase64();
|
||||
_log.error("NOTICE: ZzzOT: Your base 32 address is " + b32);
|
||||
_log.error("NOTICE: ZzzOT: Your base 64 address is " + b64);
|
||||
_log.logAlways(Log.INFO, "NOTICE: ZzzOT: Your base 32 address is " + b32);
|
||||
_log.logAlways(Log.INFO, "NOTICE: ZzzOT: Your base 64 address is " + b64);
|
||||
}
|
||||
startJetty(pluginDir, dest);
|
||||
startI2PTunnel(pluginDir, dest);
|
||||
_zzzot.start();
|
||||
// SeedlessAnnouncer.announce(_tunnel);
|
||||
}
|
||||
|
||||
|
||||
private static void startI2PTunnel(File pluginDir, Destination dest) {
|
||||
private void startI2PTunnel(File pluginDir, Destination dest) {
|
||||
File i2ptunnelConfig = new File(pluginDir, "i2ptunnel.config");
|
||||
Properties i2ptunnelProps = new Properties();
|
||||
try {
|
||||
@ -131,15 +194,15 @@ public class ZzzOTController {
|
||||
_tunnel = tun;
|
||||
}
|
||||
|
||||
private static void startJetty(File pluginDir, Destination dest) {
|
||||
private void startJetty(File pluginDir, Destination dest) {
|
||||
if (_server != null)
|
||||
throw new IllegalArgumentException("Jetty already running!");
|
||||
migrateJettyXML(pluginDir);
|
||||
I2PAppContext context = I2PAppContext.getGlobalContext();
|
||||
File tmpdir = new File(context.getTempDir().getAbsolutePath(), "/zzzot-work");
|
||||
File tmpdir = new File(_context.getTempDir().getAbsolutePath(), "/zzzot-work");
|
||||
tmpdir.mkdir();
|
||||
File jettyXml = new File(pluginDir, "jetty.xml");
|
||||
try {
|
||||
Resource.setDefaultUseCaches(false);
|
||||
XmlConfiguration xmlc = new XmlConfiguration(jettyXml.toURI().toURL());
|
||||
Server serv = (Server) xmlc.configure();
|
||||
//HttpContext[] hcs = serv.getContexts();
|
||||
@ -155,18 +218,26 @@ public class ZzzOTController {
|
||||
launchHelp(pluginDir, dest);
|
||||
}
|
||||
|
||||
private static void stop() {
|
||||
private void stop() {
|
||||
stopI2PTunnel();
|
||||
stopJetty();
|
||||
if (_zzzot != null)
|
||||
_zzzot.stop();
|
||||
_zzzot.stop();
|
||||
}
|
||||
|
||||
private static void stopI2PTunnel() {
|
||||
private void stopI2PTunnel() {
|
||||
if (_tunnel == null)
|
||||
return;
|
||||
try {
|
||||
_tunnel.stopTunnel();
|
||||
// destroyTunnel() not available until 0.9.17
|
||||
if (VersionComparator.comp(CoreVersion.VERSION, "0.9.17") >= 0) {
|
||||
try {
|
||||
_tunnel.destroyTunnel();
|
||||
} catch (Throwable t) {
|
||||
_tunnel.stopTunnel();
|
||||
}
|
||||
} else {
|
||||
_tunnel.stopTunnel();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
_log.error("ZzzOT tunnel stop failed", t);
|
||||
throw new IllegalArgumentException("Tunnel stop failed " + t);
|
||||
@ -174,7 +245,7 @@ public class ZzzOTController {
|
||||
_tunnel = null;
|
||||
}
|
||||
|
||||
private static void stopJetty() {
|
||||
private void stopJetty() {
|
||||
if (_server == null)
|
||||
return;
|
||||
try {
|
||||
@ -190,35 +261,66 @@ public class ZzzOTController {
|
||||
* Migate the jetty configuration files.
|
||||
* Save old jetty.xml if moving from jetty 5 to jetty 6
|
||||
*/
|
||||
private static void migrateJettyXML(File pluginDir) {
|
||||
private void migrateJettyXML(File pluginDir) {
|
||||
// contexts dir does not exist in Jetty 5
|
||||
File file = new File(pluginDir, "contexts");
|
||||
if (file.exists())
|
||||
return;
|
||||
file.mkdir();
|
||||
file = new File(pluginDir, "etc");
|
||||
file.mkdir();
|
||||
file = new File(pluginDir, "jetty.xml");
|
||||
if (file.exists()) {
|
||||
File backup = new File(pluginDir, BACKUP);
|
||||
if (backup.exists()) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
backup = new File(pluginDir, BACKUP + ctx.random().nextInt());
|
||||
}
|
||||
boolean ok = FileUtil.copy(file, backup, false, true);
|
||||
if (!ok) {
|
||||
_log.error("WARNING: Failed to back up " + file + " to " + backup);
|
||||
}
|
||||
}
|
||||
if (!shouldMigrate(file))
|
||||
return;
|
||||
for (int i = 0; i < xmlFiles.length; i++) {
|
||||
migrateJettyFile(pluginDir, xmlFiles[i]);
|
||||
backupAndMigrateFile(pluginDir, xmlFiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return should we copy over all the files, based on the contents of this one
|
||||
* @since 0.10 (Jetty 7)
|
||||
*/
|
||||
private static boolean shouldMigrate(File f) {
|
||||
String xml = FileUtil.readTextFile(f.getAbsolutePath(), 400, true);
|
||||
if (xml == null)
|
||||
return true;
|
||||
return xml.contains("class=\"org.eclipse.jetty.server.nio.SelectChannelConnector\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup a file and migrate new XML
|
||||
* @return success
|
||||
* @since Jetty 7
|
||||
*/
|
||||
private boolean backupAndMigrateFile(File toDir, String filename) {
|
||||
File to = new File(toDir, filename);
|
||||
boolean rv = backupFile(to);
|
||||
boolean rv2 = migrateJettyFile(toDir, filename);
|
||||
return rv && rv2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup a file
|
||||
* @return success
|
||||
* @since Jetty 7
|
||||
*/
|
||||
private static boolean backupFile(File from) {
|
||||
if (!from.exists())
|
||||
return true;
|
||||
File to = new File(from.getAbsolutePath() + BACKUP_SUFFIX);
|
||||
if (to.exists())
|
||||
to = new File(to.getAbsolutePath() + "." + System.currentTimeMillis());
|
||||
boolean rv = FileUtil.copy(from, to, false, true);
|
||||
if (rv)
|
||||
System.err.println("Backed up file " + from + " to " + to);
|
||||
else
|
||||
System.err.println("WARNING: Failed to back up file " + from + " to " + to);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migate a single jetty config file, replacing $PLUGIN as we copy it.
|
||||
*/
|
||||
private static void migrateJettyFile(File pluginDir, String name) {
|
||||
private boolean migrateJettyFile(File pluginDir, String name) {
|
||||
File templateDir = new File(pluginDir, "templates");
|
||||
File fileTmpl = new File(templateDir, name);
|
||||
File outFile = new File(pluginDir, name);
|
||||
@ -230,15 +332,17 @@ public class ZzzOTController {
|
||||
props = props.replace("$PLUGIN", pluginDir.getAbsolutePath());
|
||||
os = new FileOutputStream(outFile);
|
||||
os.write(props.getBytes("UTF-8"));
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
_log.error(outFile + " migrate failed", ioe);
|
||||
return false;
|
||||
} finally {
|
||||
if (os != null) try { os.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/** put the directory, base32, and base64 info in the help.html file and launch a browser window to display it */
|
||||
private static void launchHelp(File pluginDir, Destination dest) {
|
||||
private void launchHelp(File pluginDir, Destination dest) {
|
||||
File fileTmpl = new File(pluginDir, "templates/help.html");
|
||||
File outFile = new File(pluginDir, "eepsite/docroot/help.html");
|
||||
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||
@ -265,4 +369,83 @@ public class ZzzOTController {
|
||||
UrlLauncher.main(new String[] { "http://127.0.0.1:7662/help.html" } );
|
||||
}
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
/** @since 0.12.0 */
|
||||
public synchronized void startup() {
|
||||
if (_mgr != null) {
|
||||
// this is really ugly, but thru 0.9.16,
|
||||
// stopping a ClientApp plugin with $PLUGIN in the args fails,
|
||||
// and it tries to start a second one instead.
|
||||
// Find the first one and stop it.
|
||||
ClientApp z = _mgr.getRegisteredApp(NAME);
|
||||
if (z != null) {
|
||||
if (VersionComparator.comp(CoreVersion.VERSION, "0.9.17") < 0) {
|
||||
ZzzOTController ctrlr = (ZzzOTController) z;
|
||||
_log.warn("Got start when another zzzot running, stopping him instead");
|
||||
ctrlr.shutdown(null);
|
||||
} else {
|
||||
_log.error("ZzzOT already running");
|
||||
}
|
||||
changeState(START_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (_state != STOPPED && _state != INITIALIZED && _state != START_FAILED) {
|
||||
_log.error("Start while state = " + _state);
|
||||
return;
|
||||
}
|
||||
changeState(STARTING);
|
||||
try {
|
||||
start(_args);
|
||||
changeState(RUNNING);
|
||||
if (_mgr != null)
|
||||
_mgr.register(this);
|
||||
} catch (Exception e) {
|
||||
changeState(START_FAILED, "Start failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.12.0 */
|
||||
public synchronized void shutdown(String[] args) {
|
||||
if (_state == STOPPED)
|
||||
return;
|
||||
changeState(STOPPING);
|
||||
if (_mgr != null)
|
||||
_mgr.unregister(this);
|
||||
stop();
|
||||
changeState(STOPPED);
|
||||
}
|
||||
|
||||
/** @since 0.12.0 */
|
||||
public ClientAppState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/** @since 0.12.0 */
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/** @since 0.12.0 */
|
||||
public String getDisplayName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/////// end ClientApp methods
|
||||
|
||||
/** @since 0.12.0 */
|
||||
private synchronized void changeState(ClientAppState state) {
|
||||
_state = state;
|
||||
if (_mgr != null)
|
||||
_mgr.notify(this, state, null, null);
|
||||
}
|
||||
|
||||
/** @since 0.12.0 */
|
||||
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
|
||||
_state = state;
|
||||
if (_mgr != null)
|
||||
_mgr.notify(this, state, msg, e);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<%@page import="java.util.ArrayList" %><%@page import="java.util.Collections" %><%@page import="java.util.List" %><%@page import="java.util.Map" %><%@page import="java.util.HashMap" %><%@page import="net.i2p.data.Base64" %><%@page import="net.i2p.data.Destination" %><%@page import="net.i2p.zzzot.*" %><%@page import="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
|
||||
@ -27,12 +27,15 @@
|
||||
*/
|
||||
// would be nice to make these configurable
|
||||
final int MAX_RESPONSES = 25;
|
||||
final int INTERVAL = 27*60;
|
||||
final boolean ALLOW_IP_MISMATCH = false;
|
||||
final boolean ALLOW_COMPACT_RESPONSE = true;
|
||||
|
||||
// so the chars will turn into bytes correctly
|
||||
request.setCharacterEncoding("ISO-8859-1");
|
||||
// above doesn't work for the query string
|
||||
// https://wiki.eclipse.org/Jetty/Howto/International_Characters
|
||||
// we could also do ((org.eclipse.jetty.server.Request) request).setQueryEncoding("ISO-8859-1")
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
|
||||
java.io.OutputStream cout = response.getOutputStream();
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
response.setContentType("text/plain");
|
||||
@ -61,7 +64,8 @@
|
||||
if (xff != null || xfs != null) {
|
||||
fail = true;
|
||||
msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
//response.setStatus(403, msg);
|
||||
response.setStatus(403);
|
||||
}
|
||||
|
||||
if (info_hash == null && !fail) {
|
||||
@ -69,6 +73,11 @@
|
||||
msg = "no info hash";
|
||||
}
|
||||
|
||||
if (!fail && info_hash.length() != 20) {
|
||||
fail = true;
|
||||
msg = "bad info hash length " + info_hash.length();
|
||||
}
|
||||
|
||||
if (ip == null && !fail) {
|
||||
fail = true;
|
||||
msg = "no ip (dest)";
|
||||
@ -79,11 +88,22 @@
|
||||
msg = "no peer id";
|
||||
}
|
||||
|
||||
if (!fail && peer_id.length() != 20) {
|
||||
fail = true;
|
||||
msg = "bad peer id length " + peer_id.length();
|
||||
}
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
if (torrents == null && !fail) {
|
||||
fail = true;
|
||||
msg = "tracker is down";
|
||||
}
|
||||
|
||||
InfoHash ih = null;
|
||||
if (!fail) {
|
||||
try {
|
||||
ih = new InfoHash(info_hash);
|
||||
} catch (Exception e) {
|
||||
ih = torrents.createInfoHash(info_hash);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail = true;
|
||||
msg = "bad infohash " + e;
|
||||
}
|
||||
@ -94,7 +114,10 @@
|
||||
try {
|
||||
if (ip.endsWith(".i2p"))
|
||||
ip = ip.substring(0, ip.length() - 4);
|
||||
d = new Destination(ip); // from b64 string
|
||||
byte[] b = Base64.decode(ip);
|
||||
if (b == null)
|
||||
throw new Exception();
|
||||
d = Destination.create(new ByteArrayInputStream(b)); // cache
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad dest " + e;
|
||||
@ -104,8 +127,8 @@
|
||||
PID pid = null;
|
||||
if (!fail) {
|
||||
try {
|
||||
pid = new PID(peer_id);
|
||||
} catch (Exception e) {
|
||||
pid = torrents.createPID(peer_id);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail = true;
|
||||
msg = "bad peer id " + e;
|
||||
}
|
||||
@ -155,15 +178,14 @@
|
||||
} catch (NumberFormatException nfe) {};
|
||||
}
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
Map<String, Object> m = new HashMap();
|
||||
Map<String, Object> m = new HashMap<String, Object>(8);
|
||||
if (fail) {
|
||||
m.put("failure reason", msg);
|
||||
} else if ("stopped".equals(event)) {
|
||||
Peers peers = torrents.get(ih);
|
||||
if (matchIP && peers != null)
|
||||
peers.remove(pid);
|
||||
m.put("interval", Integer.valueOf(INTERVAL));
|
||||
m.put("interval", torrents.getInterval());
|
||||
} else {
|
||||
Peers peers = torrents.get(ih);
|
||||
if (peers == null) {
|
||||
@ -176,7 +198,8 @@
|
||||
// fixme same peer id, different dest
|
||||
Peer p = peers.get(pid);
|
||||
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
|
||||
if (matchIP) {
|
||||
Peer p2 = peers.putIfAbsent(pid, p);
|
||||
@ -188,7 +211,7 @@
|
||||
if (matchIP)
|
||||
p.setLeft(left);
|
||||
|
||||
m.put("interval", Integer.valueOf(INTERVAL));
|
||||
m.put("interval", torrents.getInterval());
|
||||
int size = peers.size();
|
||||
int seeds = peers.countSeeds();
|
||||
m.put("complete", Integer.valueOf(seeds));
|
||||
@ -197,11 +220,20 @@
|
||||
// snark < 0.7.13 always wants a list
|
||||
m.put("peers", java.util.Collections.EMPTY_LIST);
|
||||
} else {
|
||||
List<Peer> peerlist = new ArrayList(peers.values());
|
||||
List<Peer> peerlist = new ArrayList<Peer>(peers.values());
|
||||
peerlist.remove(p); // them
|
||||
if (want < size - 1) {
|
||||
Collections.shuffle(peerlist);
|
||||
peerlist = peerlist.subList(0, want);
|
||||
if (size > 150) {
|
||||
// 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) {
|
||||
// old experimental way - list of hashes
|
||||
|
@ -1,4 +1,4 @@
|
||||
<%@page import="net.i2p.zzzot.ZzzOTController" %>
|
||||
<%@page import="net.i2p.zzzot.ZzzOTController,net.i2p.zzzot.Torrents" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>ZzzOT</title>
|
||||
@ -6,9 +6,20 @@
|
||||
<p>
|
||||
zzzot
|
||||
<p>
|
||||
<%
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
if (torrents != null) {
|
||||
%>
|
||||
<table cellspacing="8">
|
||||
<tr><td>Torrents:<td align="right"><%=ZzzOTController.getTorrents().size()%>
|
||||
<tr><td>Peers:<td align="right"><%=ZzzOTController.getTorrents().countPeers()%>
|
||||
<tr><td>Torrents:<td align="right"><%=torrents.size()%>
|
||||
<tr><td>Peers:<td align="right"><%=torrents.countPeers()%>
|
||||
</table>
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
ZzzOT is not running
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<%@page import="java.util.ArrayList" %><%@page import="java.util.List" %><%@page import="java.util.Map" %><%@page import="java.util.HashMap" %><%@page import="net.i2p.zzzot.*" %><%@page import="org.klomp.snark.bencode.BEncoder" %><%
|
||||
<%@page import="java.util.ArrayList,java.util.List,java.util.Map,java.util.HashMap,net.i2p.zzzot.*,org.klomp.snark.bencode.BEncoder" %><%
|
||||
|
||||
/*
|
||||
* Above one-liner is so there is no whitespace -> IllegalStateException
|
||||
@ -27,6 +27,10 @@
|
||||
*/
|
||||
// so the chars will turn into bytes correctly
|
||||
request.setCharacterEncoding("ISO-8859-1");
|
||||
// above doesn't work for the query string
|
||||
// https://wiki.eclipse.org/Jetty/Howto/International_Characters
|
||||
// we could also do ((org.eclipse.jetty.server.Request) request).setQueryEncoding("ISO-8859-1")
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
|
||||
java.io.OutputStream cout = response.getOutputStream();
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
response.setContentType("text/plain");
|
||||
@ -41,39 +45,44 @@
|
||||
if (xff != null || xfs != null) {
|
||||
fail = true;
|
||||
msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
//response.setStatus(403, msg);
|
||||
response.setStatus(403);
|
||||
}
|
||||
|
||||
boolean all = info_hash == null;
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
if (torrents == null && !fail) {
|
||||
fail = true;
|
||||
msg = "tracker is down";
|
||||
}
|
||||
|
||||
InfoHash ih = null;
|
||||
if ((!all) && !fail) {
|
||||
try {
|
||||
ih = new InfoHash(info_hash);
|
||||
ih = torrents.createInfoHash(info_hash);
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad infohash " + e;
|
||||
}
|
||||
}
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
|
||||
// build 3-level dictionary
|
||||
Map<String, Object> m = new HashMap();
|
||||
Map<String, Object> m = new HashMap<String, Object>(4);
|
||||
if (fail) {
|
||||
m.put("failure reason", msg);
|
||||
} else {
|
||||
List<InfoHash> ihList = new ArrayList();
|
||||
List<InfoHash> ihList = new ArrayList<InfoHash>();
|
||||
if (all)
|
||||
ihList.addAll(torrents.keySet());
|
||||
else
|
||||
ihList.add(ih);
|
||||
Map<String, Map> files = new HashMap();
|
||||
Map<String, Map> files = new HashMap<String, Map>();
|
||||
for (InfoHash ihash : ihList) {
|
||||
Peers peers = torrents.get(ihash);
|
||||
if (peers == null)
|
||||
continue;
|
||||
Map<String, Object> dict = new HashMap();
|
||||
Map<String, Object> dict = new HashMap<String, Object>();
|
||||
int size = peers.size();
|
||||
int seeds = peers.countSeeds();
|
||||
dict.put("complete", Integer.valueOf(seeds));
|
||||
|
@ -1,4 +1,4 @@
|
||||
<%@page import="net.i2p.crypto.SHA256Generator" %><%@page import="net.i2p.data.Base32" %><%@page import="net.i2p.data.Base64" %><%@page import="net.i2p.data.DataHelper" %><%@page import="net.i2p.zzzot.*" %><%
|
||||
<%@page import="net.i2p.crypto.SHA256Generator,net.i2p.data.Base32,net.i2p.data.Base64,net.i2p.data.DataHelper,net.i2p.zzzot.*" %><%
|
||||
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
@ -40,7 +40,8 @@
|
||||
|
||||
if (xff != null || xfs != null) {
|
||||
String msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
//response.setStatus(403, msg);
|
||||
response.setStatus(403);
|
||||
out.println(msg);
|
||||
} else if (req == null) {
|
||||
// probe
|
||||
@ -62,6 +63,11 @@
|
||||
} else if (req.startsWith("locate dG9ycmVud")) { // locate b64(torrent)
|
||||
// all the peers
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
if (torrents == null) {
|
||||
//response.setStatus(503, "Down");
|
||||
response.setStatus(503);
|
||||
return;
|
||||
}
|
||||
for (InfoHash ihash : torrents.keySet()) {
|
||||
Peers peers = torrents.get(ihash);
|
||||
if (peers == null)
|
||||
@ -88,7 +94,8 @@
|
||||
}
|
||||
} else {
|
||||
// error code
|
||||
response.setStatus(406, "Bad request");
|
||||
//response.setStatus(406, "Bad request");
|
||||
response.setStatus(406);
|
||||
out.println("SC_NOT_ACCEPTABLE");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user