17 Commits

Author SHA1 Message Date
zzz
953533c6e3 0.12.0 2014-11-13 20:15:02 +00:00
zzz
2e0f7ae4bf Release all resources when shut down (requires 0.9.16-6 or higher)
log tweaks
2014-11-13 16:01:15 +00:00
zzz
17e5595dd0 Don't overwrite index.html and robots.txt in the update
More build and clean fixes
2014-11-12 23:10:19 +00:00
zzz
8350d009d4 Add zzzot.config file to set interval 2014-11-12 15:19:13 +00:00
zzz
a7225a2379 Fix parameter decoding for scrape also
Add caching for info hashes and peer ids; move from ByteArray to SDS
Stop cleaner when plugin stops
Move to the ClientApp interface, remove all static refs
Attempt to fix crash after update
2014-11-12 14:48:51 +00:00
zzz
8a9094cd8e Fix critical bug preventing announces from working
0.11.0
2014-11-11 14:08:43 +00:00
zzz
7f4394aa0f add max-jetty-version 2014-10-24 14:43:51 +00:00
zzz
38f38398ef switch Jetty to QTP 2014-10-24 13:01:28 +00:00
zzz
8317e3ce9a Change new install logging from ERROR to INFO
Move up warning about removing help file
2014-08-30 14:03:56 +00:00
zzz
c1f6a14367 add su3 url 2014-08-09 18:47:16 +00:00
zzz
7e36455b05 add support for building su3 plugins 2014-08-09 18:00:17 +00:00
zzz
a85aa6af31 more import cleanup 2014-08-09 16:25:44 +00:00
zzz
f33303f394 Use cached Destinations
Specify min I2P version of 0.9.9 for Destination.create()
2014-08-09 16:21:02 +00:00
zzz
ab882f8582 0.10.0:
Updates and migration for Jetty 7 (I2P 0.9.6)
2013-04-15 14:09:10 +00:00
zzz
ce7562c547 0.9.0:
Add cache-control directives
  Set max Jetty to 6.99999
2013-01-25 20:56:04 +00:00
zzz
52d8e26ffc add changelog 2012-03-11 14:40:20 +00:00
zzz
284d7a58d6 0.8 fix comment in jetty.xml 2012-03-10 23:55:21 +00:00
22 changed files with 755 additions and 241 deletions

66
CHANGES.txt Normal file
View File

@ -0,0 +1,66 @@
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

View File

@ -8,10 +8,14 @@
</target> </target>
<target name="plugin" depends="war"> <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 --> <!-- get version number -->
<buildnumber file="scripts/build.number" /> <buildnumber file="scripts/build.number" />
<property name="release.number" value="0.7" /> <property name="release.number" value="0.12.0" />
<!-- make the update xpi2p --> <!-- make the update xpi2p -->
<!-- this contains everything except i2ptunnel.config --> <!-- this contains everything except i2ptunnel.config -->
@ -34,18 +38,31 @@
<arg value="plugin/eepsite/webapps/tracker.war.pack" /> <arg value="plugin/eepsite/webapps/tracker.war.pack" />
<arg value="src/build/tracker.war.jar" /> <arg value="src/build/tracker.war.jar" />
</exec> </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" /> <arg value="plugin" />
</exec> </exec>
<move file="zzzot.xpi2p" tofile="zzzot-update.xpi2p" overwrite="true" /> <move file="zzzot.xpi2p" tofile="zzzot-update.xpi2p" overwrite="true" />
<move file="zzzot.su3" tofile="zzzot-update.su3" overwrite="true" />
<!-- make the install xpi2p --> <!-- make the install xpi2p -->
<copy file="scripts/i2ptunnel.config" todir="plugin/" overwrite="true" />
<copy file="scripts/plugin.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"> <exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
<arg value="version=${release.number}-b${build.number}" /> <arg value="version=${release.number}-b${build.number}" />
</exec> </exec>
<exec executable="scripts/makeplugin.sh" failonerror="true" > <exec executable="scripts/makeplugin.sh" inputstring="${release.password.su3}" failonerror="true" >
<arg value="plugin" /> <arg value="plugin" />
</exec> </exec>
</target> </target>
@ -56,12 +73,19 @@
<ant dir="src" target="clean" /> <ant dir="src" target="clean" />
<delete file="plugin/i2ptunnel.config" /> <delete file="plugin/i2ptunnel.config" />
<delete file="plugin/plugin.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/lib/zzzot.jar.pack" />
<delete file="plugin/eepsite/webapps/tracker.war.pack" /> <delete file="plugin/eepsite/webapps/tracker.war.pack" />
<delete file="plugin/LICENSE.txt" /> <delete file="plugin/LICENSE.txt" />
<delete file="plugin/README.txt" /> <delete file="plugin/README.txt" />
<delete file="zzzot.xpi2p" /> <delete file="zzzot.xpi2p" />
<delete file="zzzot-update.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> </target>
</project> </project>

View File

@ -1,18 +1,22 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?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. 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. 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="contextPath">/</Set>
<Set name="resourceBase">$PLUGIN/eepsite/docroot/</Set> <Set name="resourceBase">$PLUGIN/eepsite/docroot/</Set>
<Call name="setInitParameter">
<Arg>cacheControl</Arg>
<Arg>max-age=3600,public</Arg>
</Call>
<Call name="addServlet"> <Call name="addServlet">
<Arg>org.mortbay.jetty.servlet.DefaultServlet</Arg> <Arg>org.eclipse.jetty.servlet.DefaultServlet</Arg>
<Arg>/</Arg> <Arg>/</Arg>
</Call> </Call>
</Configure> </Configure>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?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. Configure a custom context for the eepsite.
@ -22,21 +22,15 @@ Configure a custom context for the eepsite.
* parameter value. * parameter value.
--> -->
<Configure class="org.mortbay.jetty.servlet.Context"> <Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
<Set name="contextPath">/cgi-bin</Set> <Set name="contextPath">/cgi-bin</Set>
<Set name="resourceBase">$PLUGIN/eepsite/cgi-bin/</Set> <Set name="resourceBase">$PLUGIN/eepsite/cgi-bin/</Set>
<Call name="setInitParams"> <Call name="setInitParameter">
<Arg> <Arg>Path</Arg>
<Map> <Arg>/usr/local/bin:/bin:/usr/bin</Arg>
<Entry>
<Item>Path</Item>
<Item>/usr/local/bin:/bin:/usr/bin</Item>
</Entry>
</Map>
</Arg>
</Call> </Call>
<Call name="addServlet"> <Call name="addServlet">
<Arg>org.mortbay.servlet.CGI</Arg> <Arg>org.eclipse.jetty.servlets.CGI</Arg>
<Arg>/</Arg> <Arg>/</Arg>
</Call> </Call>
</Configure> </Configure>

View File

@ -35,23 +35,23 @@
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- UNCOMMENT TO ACTIVATE <!-- UNCOMMENT TO ACTIVATE
<context-param> <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> <param-value>127.0.0.1</param-value>
</context-param> </context-param>
<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> <param-value>/</param-value>
</context-param> </context-param>
<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> <param-value>-1</param-value>
</context-param> </context-param>
--> -->
<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> <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> </context-param>
@ -112,7 +112,7 @@
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<servlet> <servlet>
<servlet-name>default</servlet-name> <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> <init-param>
<param-name>acceptRanges</param-name> <param-name>acceptRanges</param-name>
<param-value>true</param-value> <param-value>true</param-value>
@ -153,12 +153,10 @@
<param-name>useFileMappedBuffer</param-name> <param-name>useFileMappedBuffer</param-name>
<param-value>true</param-value> <param-value>true</param-value>
</init-param> </init-param>
<!--
<init-param> <init-param>
<param-name>cacheControl</param-name> <param-name>cacheControl</param-name>
<param-value>max-age=3600,public</param-value> <param-value>max-age=3600,public</param-value>
</init-param> </init-param>
-->
<load-on-startup>0</load-on-startup> <load-on-startup>0</load-on-startup>
</servlet> </servlet>
@ -308,7 +306,7 @@
<!-- Uncomment for dynamic invocation <!-- Uncomment for dynamic invocation
<servlet> <servlet>
<servlet-name>invoker</servlet-name> <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> <init-param>
<param-name>verbose</param-name> <param-name>verbose</param-name>
<param-value>false</param-value> <param-value>false</param-value>

View File

@ -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 <p>Report bugs or add comments on
<a href="http://zzz.i2p//forums/16">the plugin forum on zzz.i2p</a>. <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> <h3>Eepsite Key and Helpful Hints for I2P</h3>
<p>Your Base 32 address is <a href="http://$B32/">$B32</a>. <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. 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 <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. 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, <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 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>. the eepsite, for example at <a href="http://$B32/torrents/">/torrents</a>.

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?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. --> <!-- This file configures the Jetty server. -->
@ -8,21 +8,21 @@
<!-- Commonly changed settings: --> <!-- Commonly changed settings: -->
<!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section --> <!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section -->
<!-- to access the server directly (bypassing i2p) --> <!-- to access the server directly (bypassing i2p) -->
<!-- from other computers. <!-- from other computers. -->
<!-- * port: Default 7662 in the addConnector section --> <!-- * port: Default 7662 in the addConnector section -->
<!-- * docroot: Change the ResourceBase in the addContext section --> <!-- * docroot: Change the ResourceBase in the contexts/base-context.xml file -->
<!-- to serve files from a different location. --> <!-- 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. --> <!-- 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 --> <!-- I2P uses Jetty 7. If you need web server features not found -->
<!-- in Jetty 6, you may install and run Jetty 7 or 8 in a different JVM --> <!-- in Jetty 7, you may install and run Jetty 7 or 8 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 6 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. -->
<!-- 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. --> <!-- Note that the XML encoding for this file is UTF-8. -->
<!-- --> <!-- -->
@ -37,7 +37,7 @@
<!-- =============================================================== --> <!-- =============================================================== -->
<Configure id="Server" class="org.mortbay.jetty.Server"> <Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Server Thread Pool --> <!-- Server Thread Pool -->
@ -46,30 +46,57 @@
<!-- PICK ONE --> <!-- PICK ONE -->
<!-- If you don't have or want threadpool <!--
Requests above the max will be queued Recommended.
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.eclipse.jetty.util.thread.QueuedThreadPool">
<New class="org.mortbay.thread.QueuedThreadPool"> <Arg>
<Set name="minThreads">1</Set> <New class="java.util.concurrent.LinkedBlockingQueue">
<Set name="maxThreads">16</Set> <Arg type="int">50</Arg>
<Set name="lowThreads">2</Set> </New>
</Arg>
<Set name="minThreads">4</Set>
<Set name="maxThreads">20</Set>
<Set name="maxIdleTimeMs">60000</Set>
<Set name="daemon">true</Set>
<Set name="name">Zzzot Jetty</Set>
</New> </New>
-->
<!-- Optional Java 5 bounded threadpool with job queue <!-- Optional Java 5 bounded threadpool with job queue
Requests above the max will be rejected Requests above the max will be rejected and logged.
TODO: would be nice to use the 5-arg constructor but High-traffic sites should increase maximumPoolSize.
how do you use an Enum as the TimeUnit argument?
Alternatively, make a custom class where we can Args are:
set the thread name, set daemon, etc. corePoolSize (should be at least 3)
See RouterConsoleRunner. 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.mortbay.thread.concurrent.ThreadPool"> <!--
<Arg type="int">0</Arg> <New class="org.eclipse.jetty.util.thread.ExecutorThreadPool">
<Set name="corePoolSize">1</Set> <Arg type="int">3</Arg>
<Set name="maximumPoolSize">16</Set> <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> </New>
-->
</Set> </Set>
@ -82,10 +109,14 @@
<!-- Use this connector for many frequently idle connections <!-- Use this connector for many frequently idle connections
and for threadless continuations. 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"> <Call name="addConnector">
<Arg> <Arg>
<New class="org.mortbay.jetty.nio.SelectChannelConnector"> <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
<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="maxIdleTime">60000</Set>
@ -94,16 +125,35 @@
<Set name="confidentialPort">8443</Set> <Set name="confidentialPort">8443</Set>
<Set name="lowResourcesConnections">5000</Set> <Set name="lowResourcesConnections">5000</Set>
<Set name="lowResourcesMaxIdleTime">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 -->
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- <!--
<Set name="sessionIdManager"> <Set name="sessionIdManager">
<New class="org.mortbay.jetty.servlet.HashSessionIdManager"> <New class="org.eclipse.jetty.server.session.HashSessionIdManager">
<Set name="workerName">node1</Set> <Set name="workerName">node1</Set>
</New> </New>
</Set> </Set>
@ -118,74 +168,74 @@
<!-- that is hosted on the same eepsite. --> <!-- that is hosted on the same eepsite. -->
<!-- =========================================================== --> <!-- =========================================================== -->
<Set name="handler"> <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="rewriteRequestURI">true</Set>
<Set name="rewritePathInfo">false</Set> <Set name="rewritePathInfo">false</Set>
<Set name="originalPathAttribute">requestedPath</Set> <Set name="originalPathAttribute">requestedPath</Set>
<Set name="rules"> <Set name="rules">
<Array type="org.mortbay.jetty.handler.rewrite.Rule"> <Array type="org.eclipse.jetty.rewrite.handler.Rule">
<Item> <Item>
<New class="org.mortbay.jetty.handler.rewrite.RewritePatternRule"> <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
<Set name="pattern">/a</Set> <Set name="pattern">/a</Set>
<Set name="replacement">/tracker/announce.jsp</Set> <Set name="replacement">/tracker/announce.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/announce</Set>
<Set name="replacement">/tracker/announce.jsp</Set> <Set name="replacement">/tracker/announce.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/announce.jsp</Set>
<Set name="replacement">/tracker/announce.jsp</Set> <Set name="replacement">/tracker/announce.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/announce.php</Set>
<Set name="replacement">/tracker/announce.jsp</Set> <Set name="replacement">/tracker/announce.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/scrape</Set>
<Set name="replacement">/tracker/scrape.jsp</Set> <Set name="replacement">/tracker/scrape.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/scrape.jsp</Set>
<Set name="replacement">/tracker/scrape.jsp</Set> <Set name="replacement">/tracker/scrape.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/scrape.php</Set>
<Set name="replacement">/tracker/scrape.jsp</Set> <Set name="replacement">/tracker/scrape.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/Seedless</Set>
<Set name="replacement">/tracker/seedless.jsp</Set> <Set name="replacement">/tracker/seedless.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/Seedless/</Set>
<Set name="replacement">/tracker/seedless.jsp</Set> <Set name="replacement">/tracker/seedless.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/Seedless/index.jsp</Set>
<Set name="replacement">/tracker/seedless.jsp</Set> <Set name="replacement">/tracker/seedless.jsp</Set>
</New> </New>
</Item> </Item>
<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="pattern">/Seedless/seedless</Set>
<Set name="replacement">/tracker/seedless.jsp</Set> <Set name="replacement">/tracker/seedless.jsp</Set>
</New> </New>
@ -193,17 +243,17 @@
</Array> </Array>
</Set> </Set>
<Set name="handler"> <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"> <Set name="handlers">
<Array type="org.mortbay.jetty.Handler"> <Array type="org.eclipse.jetty.server.Handler">
<Item> <Item>
<New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/> <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
</Item> </Item>
<Item> <Item>
<New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/> <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</Item> </Item>
<Item> <Item>
<New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/> <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
</Item> </Item>
</Array> </Array>
</Set> </Set>
@ -211,7 +261,32 @@
</Set> </Set>
</New> </New>
</Set> </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 --> <!-- Configure the context deployer -->
<!-- A context deployer will deploy contexts described in --> <!-- A context deployer will deploy contexts described in -->
@ -223,15 +298,16 @@
<!-- in the $JETTY_HOME/contexts directory --> <!-- in the $JETTY_HOME/contexts directory -->
<!-- --> <!-- -->
<!-- =========================================================== --> <!-- =========================================================== -->
<Call name="addLifeCycle"> <Ref id="DeploymentManager">
<Arg> <Call name="addAppProvider">
<New class="org.mortbay.jetty.deployer.ContextDeployer"> <Arg>
<Set name="contexts"><Ref id="Contexts"/></Set> <New class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="configurationDir">$PLUGIN/contexts</Set> <Set name="monitoredDirName">$PLUGIN/contexts</Set>
<Set name="scanInterval">0</Set> <Set name="scanInterval">120</Set>
</New> </New>
</Arg> </Arg>
</Call> </Call>
</Ref>
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Configure the webapp deployer. --> <!-- Configure the webapp deployer. -->
@ -246,18 +322,18 @@
<!-- Normally only one type of deployer need be used. --> <!-- Normally only one type of deployer need be used. -->
<!-- --> <!-- -->
<!-- =========================================================== --> <!-- =========================================================== -->
<Call name="addLifeCycle"> <Ref id="DeploymentManager">
<Arg> <Call id="webappprovider" name="addAppProvider">
<New class="org.mortbay.jetty.deployer.WebAppDeployer"> <Arg>
<Set name="contexts"><Ref id="Contexts"/></Set> <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="webAppDir">$PLUGIN/eepsite/webapps</Set> <Set name="monitoredDirName">$PLUGIN/eepsite/webapps</Set>
<Set name="parentLoaderPriority">false</Set> <Set name="parentLoaderPriority">false</Set>
<Set name="extract">true</Set> <Set name="extractWars">false</Set>
<Set name="allowDuplicates">false</Set> <Set name="defaultsDescriptor">$PLUGIN/etc/webdefault.xml</Set>
<Set name="defaultsDescriptor">$PLUGIN/etc/webdefault.xml</Set> </New>
</New> </Arg>
</Arg> </Call>
</Call> </Ref>
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Configure Authentication Realms --> <!-- Configure Authentication Realms -->
@ -268,9 +344,9 @@
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- UNCOMMENT TO ACTIVATE <!-- UNCOMMENT TO ACTIVATE
<Set name="UserRealms"> <Set name="UserRealms">
<Array type="org.mortbay.jetty.security.UserRealm"> <Array type="org.eclipse.jetty.security.LoginService">
<Item> <Item>
<New class="org.mortbay.jetty.security.HashUserRealm"> <New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set> <Set name="name">Test Realm</Set>
<Set name="config">$PLUGIN/etc/realm.properties</Set> <Set name="config">$PLUGIN/etc/realm.properties</Set>
<Set name="refreshInterval">0</Set> <Set name="refreshInterval">0</Set>

View File

@ -5,11 +5,16 @@
# usage: makeplugin.sh plugindir # usage: makeplugin.sh plugindir
# #
# zzz 2010-02 # zzz 2010-02
# zzz 2014-08 added support for su3 files
# #
PUBKEYDIR=$HOME/.i2p-plugin-keys PUBKEYDIR=$HOME/.i2p-plugin-keys
PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key
PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key
B64KEYFILE=$PUBKEYDIR/plugin-public-signing.txt 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 export I2P=../i2p/pkg-temp
PLUGINDIR=${1:-plugin} PLUGINDIR=${1:-plugin}
@ -17,46 +22,67 @@ PLUGINDIR=${1:-plugin}
PC=plugin.config PC=plugin.config
PCT=${PC}.tmp 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 ] if [ ! -d $PLUGINDIR ]
then then
echo "You must have a $PLUGINDIR directory" echo "You must have a $PLUGINDIR directory"
exit 1 exit 1
fi fi
OPWD=$PWD if [ ! -f $PLUGINDIR/$PC ]
cd $PLUGINDIR
if [ ! -f $PC ]
then then
echo "You must have a $PC file" echo "You must have a $PLUGINDIR/$PC file"
exit 1 exit 1
fi fi
grep -q '^signer=' $PC SIGNER=`grep '^signer=' $PLUGINDIR/$PC`
if [ "$?" -ne "0" ] if [ "$?" -ne "0" ]
then then
echo "You must have a signer in $PC" echo "You must have a plugin name in $PC"
echo 'For example signer=joe@mail.i2p' echo 'For example name=foo'
exit 1 exit 1
fi 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 grep -q '^name=' $PC
if [ "$?" -ne "0" ] if [ "$?" -ne "0" ]
then then
echo "You must have a plugin name in $PC" echo "You must have a plugin name in $PC"
echo 'For example name=foo' echo 'For example name=foo'
exit 1 exit 1
fi fi
@ -64,7 +90,7 @@ grep -q '^version=' $PC
if [ "$?" -ne "0" ] if [ "$?" -ne "0" ]
then then
echo "You must have a version in $PC" echo "You must have a version in $PC"
echo 'For example version=0.1.2' echo 'For example version=0.1.2'
exit 1 exit 1
fi fi
@ -72,33 +98,41 @@ fi
grep -v '^date=' $PC > $PCT grep -v '^date=' $PC > $PCT
DATE=`date '+%s000'` DATE=`date '+%s000'`
echo "date=$DATE" >> $PCT echo "date=$DATE" >> $PCT
mv $PCT $PC mv $PCT $PC || exit 1
# add our Base64 key # add our Base64 key
grep -v '^key=' $PC > $PCT grep -v '^key=' $PC > $PCT
B64KEY=`cat $B64KEYFILE` B64KEY=`cat $B64KEYFILE`
echo "key=$B64KEY" >> $PCT || exit 1 echo "key=$B64KEY" >> $PCT || exit 1
mv $PCT $PC mv $PCT $PC || exit 1
# zip it # 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 # get the version and use it for the sud header
VERSION=`grep '^version=' $PC | cut -f 2 -d '='` VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
# get the name and use it for the file name # get the name and use it for the file name
NAME=`grep '^name=' $PC | cut -f 2 -d '='` NAME=`grep '^name=' $PC | cut -f 2 -d '='`
XPI2P=${NAME}.xpi2p XPI2P=${NAME}.xpi2p
SU3=${NAME}.su3
cd $OPWD cd $OPWD
# sign it # 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.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 rm -f plugin.zip
# verify # verify
echo 'Verifying. ...' echo 'Verifying. ...'
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion $XPI2P || exit 1 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 -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/ rm -rf logs/
echo -n 'Plugin created: ' echo 'Plugin files created: '
wc -c $XPI2P wc -c $XPI2P
wc -c $SU3
exit 0

View File

@ -5,6 +5,9 @@ consoleLinkURL=http://127.0.0.1:7662/tracker/index.jsp
description=Open tracker description=Open tracker
author=zzz author=zzz
updateURL=http://stats.i2p/i2p/plugins/zzzot-update.xpi2p 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 websiteURL=http://zzz.i2p/forums/16
license=Apache 2.0 license=Apache 2.0
min-jetty-version=6 min-jetty-version=7
max-jetty-version=8.9999
min-i2p-version=0.9.9

3
scripts/zzzot.config Normal file
View File

@ -0,0 +1,3 @@
# announce interval in seconds
# minimum 900 (15 minutes), maximum 21600 (6 hours)
interval=1620

View File

@ -11,10 +11,10 @@
<pathelement location="${i2plib}/mstreaming.jar" /> <pathelement location="${i2plib}/mstreaming.jar" />
<pathelement location="${ant.home}/lib/ant.jar"/> <pathelement location="${ant.home}/lib/ant.jar"/>
<pathelement location="${jettylib}/org.mortbay.jetty.jar"/> <pathelement location="${jettylib}/org.mortbay.jetty.jar"/>
<pathelement location="${jettylib}/jasper-compiler.jar" />
<pathelement location="${jettylib}/jasper-runtime.jar" /> <pathelement location="${jettylib}/jasper-runtime.jar" />
<pathelement location="${jettylib}/javax.servlet.jar" /> <pathelement location="${jettylib}/javax.servlet.jar" />
<pathelement location="${jettylib}/jetty-util.jar" /> <pathelement location="${jettylib}/jetty-util.jar" />
<pathelement location="${jettylib}/jetty-xml.jar" />
<pathelement location="${jettylib}/commons-logging.jar" /> <pathelement location="${jettylib}/commons-logging.jar" />
<pathelement location="${jettylib}/commons-el.jar" /> <pathelement location="${jettylib}/commons-el.jar" />
</path> </path>
@ -34,7 +34,7 @@
debug="true" deprecation="on" source="1.5" target="1.5" debug="true" deprecation="on" source="1.5" target="1.5"
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" > 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}" /> <compilerarg line="${javac.compilerargs}" />
</javac> </javac>
</target> </target>

View File

@ -16,22 +16,20 @@ package net.i2p.zzzot;
* *
*/ */
import java.io.UnsupportedEncodingException; import net.i2p.data.SimpleDataStructure;
import net.i2p.data.ByteArray;
/** /**
* A 20-byte SHA1 info hash * A 20-byte SHA1 info hash
*/ */
public class InfoHash extends ByteArray { public class InfoHash extends SimpleDataStructure {
public InfoHash(String data) throws UnsupportedEncodingException { public static final int LENGTH = 20;
this(data.getBytes("ISO-8859-1"));
}
public InfoHash(byte[] data) { public InfoHash(byte[] data) {
super(data); super(data);
if (data.length != 20) }
throw new IllegalArgumentException("Bad infohash length: " + data.length);
public int length() {
return LENGTH;
} }
} }

View File

@ -16,22 +16,20 @@ package net.i2p.zzzot;
* *
*/ */
import java.io.UnsupportedEncodingException; import net.i2p.data.SimpleDataStructure;
import net.i2p.data.ByteArray;
/** /**
* A 20-byte peer ID * A 20-byte peer ID
*/ */
public class PID extends ByteArray { public class PID extends SimpleDataStructure {
public PID(String data) throws UnsupportedEncodingException { public static final int LENGTH = 20;
this(data.getBytes("ISO-8859-1"));
}
public PID(byte[] data) { public PID(byte[] data) {
super(data); super(data);
if (data.length != 20) }
throw new IllegalArgumentException("Bad peer ID length: " + data.length);
public int length() {
return LENGTH;
} }
} }

View File

@ -18,13 +18,30 @@ package net.i2p.zzzot;
import java.util.concurrent.ConcurrentHashMap; 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 * All the torrents
*/ */
public class Torrents extends ConcurrentHashMap<InfoHash, Peers> { 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(); 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() { public int countPeers() {
@ -34,4 +51,60 @@ public class Torrents extends ConcurrentHashMap<InfoHash, Peers> {
} }
return rv; 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) {}
}
}
} }

View File

@ -17,34 +17,62 @@ package net.i2p.zzzot;
*/ */
import java.util.Iterator; import java.util.Iterator;
import java.util.Properties;
import net.i2p.util.SimpleScheduler; import net.i2p.I2PAppContext;
import net.i2p.util.SimpleTimer; import net.i2p.util.SimpleTimer2;
/** /**
* Instantiate this to fire it up * Instantiate this to fire it up
*/ */
class ZzzOT { class ZzzOT {
private Torrents _torrents; private final Torrents _torrents;
private static final long CLEAN_TIME = 4*60*1000; private final Cleaner _cleaner;
private static final long EXPIRE_TIME = 60*60*1000; private final long EXPIRE_TIME;
ZzzOT() { private static final String PROP_INTERVAL = "interval";
_torrents = new Torrents(); private static final long CLEAN_TIME = 4*60*1000;
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME); 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() { Torrents getTorrents() {
return _torrents; return _torrents;
} }
void stop() { void start() {
_torrents.clear(); _cleaner.forceReschedule(CLEAN_TIME);
// no way to stop the cleaner
} }
private class Cleaner implements SimpleTimer.TimedEvent { void stop() {
_cleaner.cancel();
_torrents.clear();
}
private class Cleaner extends SimpleTimer2.TimedEvent {
/** must schedule later */
public Cleaner(I2PAppContext ctx) {
super(ctx.simpleTimer2());
}
public void timeReached() { public void timeReached() {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@ -61,6 +89,7 @@ class ZzzOT {
if (recent <= 0) if (recent <= 0)
iter.remove(); iter.remove();
} }
schedule(CLEAN_TIME);
} }
} }
} }

View File

@ -22,19 +22,26 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import net.i2p.CoreVersion;
import net.i2p.I2PAppContext; 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.Base32;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.data.PrivateKeyFile; import net.i2p.data.PrivateKeyFile;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.util.FileUtil; import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.i2ptunnel.TunnelController; import net.i2p.util.VersionComparator;
import net.i2p.apps.systray.UrlLauncher;
import org.mortbay.jetty.Server; import org.eclipse.jetty.server.Server;
import org.mortbay.xml.XmlConfiguration; 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 * This handles the starting and stopping of an eepsite tunnel and jetty
@ -47,39 +54,77 @@ import org.mortbay.xml.XmlConfiguration;
* *
* @author zzz * @author zzz
*/ */
public class ZzzOTController { public class ZzzOTController implements ClientApp {
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ZzzOTController.class); private final I2PAppContext _context;
private static Server _server; private final Log _log;
private static TunnelController _tunnel; private final String[] _args;
private static ZzzOT _zzzot; private final ClientAppManager _mgr;
private static Object _lock = new Object(); 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 = ".jetty6";
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" };
public static void main(String args[]) { /**
if (args.length != 3 || (!"-d".equals(args[0]))) * @since 0.12.0
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]"); */
if ("start".equals(args[2])) public ZzzOTController(I2PAppContext ctx, ClientAppManager mgr, String args[]) {
start(args); _context = ctx;
else if ("stop".equals(args[2])) _log = ctx.logManager().getLog(ZzzOTController.class);
stop(); _mgr = mgr;
else _args = args;
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]"); File cfile = new File(_context.getAppDir(), "plugins/zzzot/" + CONFIG_FILE);
} Properties props = new Properties();
if (cfile.exists()) {
public static Torrents getTorrents() { try {
synchronized(_lock) { DataHelper.loadProps(props, cfile);
if (_zzzot == null) } catch (IOException ioe) {
_zzzot = new ZzzOT(); _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();
}
/**
* @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()) if (!pluginDir.exists())
throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist"); throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist");
@ -96,20 +141,21 @@ public class ZzzOTController {
_log.error("Unable to create " + key.getAbsolutePath() + ' ' + e); _log.error("Unable to create " + key.getAbsolutePath() + ' ' + e);
throw new IllegalArgumentException("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.logAlways(Log.INFO, "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: You should back up this file!");
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p"; String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
String b64 = dest.toBase64(); String b64 = dest.toBase64();
_log.error("NOTICE: ZzzOT: Your base 32 address is " + b32); _log.logAlways(Log.INFO, "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 64 address is " + b64);
} }
startJetty(pluginDir, dest); startJetty(pluginDir, dest);
startI2PTunnel(pluginDir, dest); startI2PTunnel(pluginDir, dest);
_zzzot.start();
// SeedlessAnnouncer.announce(_tunnel); // 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"); File i2ptunnelConfig = new File(pluginDir, "i2ptunnel.config");
Properties i2ptunnelProps = new Properties(); Properties i2ptunnelProps = new Properties();
try { try {
@ -131,15 +177,15 @@ public class ZzzOTController {
_tunnel = tun; _tunnel = tun;
} }
private static void startJetty(File pluginDir, Destination dest) { private void startJetty(File pluginDir, Destination dest) {
if (_server != null) if (_server != null)
throw new IllegalArgumentException("Jetty already running!"); throw new IllegalArgumentException("Jetty already running!");
migrateJettyXML(pluginDir); 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(); tmpdir.mkdir();
File jettyXml = new File(pluginDir, "jetty.xml"); File jettyXml = new File(pluginDir, "jetty.xml");
try { try {
Resource.setDefaultUseCaches(false);
XmlConfiguration xmlc = new XmlConfiguration(jettyXml.toURI().toURL()); XmlConfiguration xmlc = new XmlConfiguration(jettyXml.toURI().toURL());
Server serv = (Server) xmlc.configure(); Server serv = (Server) xmlc.configure();
//HttpContext[] hcs = serv.getContexts(); //HttpContext[] hcs = serv.getContexts();
@ -155,18 +201,29 @@ public class ZzzOTController {
launchHelp(pluginDir, dest); launchHelp(pluginDir, dest);
} }
private static void stop() { private void stop() {
stopI2PTunnel(); stopI2PTunnel();
stopJetty(); stopJetty();
if (_zzzot != null) _zzzot.stop();
_zzzot.stop();
} }
private static void stopI2PTunnel() { private void stopI2PTunnel() {
if (_tunnel == null) if (_tunnel == null)
return; return;
try { try {
_tunnel.stopTunnel(); // destroyTunnel() not available until 0.9.17, but we put 0.9.16 here for now
// so we get testing in 0.9.16-6 or later dev builds.
// No access to RouterVersion here.
// TODO change to 0.9.17
if (VersionComparator.comp(CoreVersion.VERSION, "0.9.16") >= 0) {
try {
_tunnel.destroyTunnel();
} catch (Throwable t) {
_tunnel.stopTunnel();
}
} else {
_tunnel.stopTunnel();
}
} catch (Throwable t) { } catch (Throwable t) {
_log.error("ZzzOT tunnel stop failed", t); _log.error("ZzzOT tunnel stop failed", t);
throw new IllegalArgumentException("Tunnel stop failed " + t); throw new IllegalArgumentException("Tunnel stop failed " + t);
@ -174,7 +231,7 @@ public class ZzzOTController {
_tunnel = null; _tunnel = null;
} }
private static void stopJetty() { private void stopJetty() {
if (_server == null) if (_server == null)
return; return;
try { try {
@ -190,35 +247,66 @@ public class ZzzOTController {
* Migate the jetty configuration files. * Migate the jetty configuration files.
* Save old jetty.xml if moving from jetty 5 to jetty 6 * 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 // contexts dir does not exist in Jetty 5
File file = new File(pluginDir, "contexts"); File file = new File(pluginDir, "contexts");
if (file.exists())
return;
file.mkdir(); file.mkdir();
file = new File(pluginDir, "etc"); file = new File(pluginDir, "etc");
file.mkdir(); file.mkdir();
file = new File(pluginDir, "jetty.xml"); file = new File(pluginDir, "jetty.xml");
if (file.exists()) { if (!shouldMigrate(file))
File backup = new File(pluginDir, BACKUP); return;
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);
}
}
for (int i = 0; i < xmlFiles.length; i++) { 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(), 100, true);
if (xml == null)
return true;
return xml.contains("class=\"org.mortbay.jetty.Server\"");
}
/**
* 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. * 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 templateDir = new File(pluginDir, "templates");
File fileTmpl = new File(templateDir, name); File fileTmpl = new File(templateDir, name);
File outFile = new File(pluginDir, name); File outFile = new File(pluginDir, name);
@ -230,15 +318,17 @@ public class ZzzOTController {
props = props.replace("$PLUGIN", pluginDir.getAbsolutePath()); props = props.replace("$PLUGIN", pluginDir.getAbsolutePath());
os = new FileOutputStream(outFile); os = new FileOutputStream(outFile);
os.write(props.getBytes("UTF-8")); os.write(props.getBytes("UTF-8"));
return true;
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error(outFile + " migrate failed", ioe); _log.error(outFile + " migrate failed", ioe);
return false;
} finally { } finally {
if (os != null) try { os.close(); } catch (IOException ioe) {} 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 */ /** 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 fileTmpl = new File(pluginDir, "templates/help.html");
File outFile = new File(pluginDir, "eepsite/docroot/help.html"); File outFile = new File(pluginDir, "eepsite/docroot/help.html");
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p"; String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
@ -265,4 +355,83 @@ public class ZzzOTController {
UrlLauncher.main(new String[] { "http://127.0.0.1:7662/help.html" } ); 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);
}
} }

View File

@ -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,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
@ -27,12 +27,15 @@
*/ */
// would be nice to make these configurable // would be nice to make these configurable
final int MAX_RESPONSES = 25; final int MAX_RESPONSES = 25;
final int INTERVAL = 27*60;
final boolean ALLOW_IP_MISMATCH = false; final boolean ALLOW_IP_MISMATCH = false;
final boolean ALLOW_COMPACT_RESPONSE = true; final boolean ALLOW_COMPACT_RESPONSE = true;
// so the chars will turn into bytes correctly // so the chars will turn into bytes correctly
request.setCharacterEncoding("ISO-8859-1"); 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(); java.io.OutputStream cout = response.getOutputStream();
response.setCharacterEncoding("ISO-8859-1"); response.setCharacterEncoding("ISO-8859-1");
response.setContentType("text/plain"); response.setContentType("text/plain");
@ -69,6 +72,11 @@
msg = "no info hash"; msg = "no info hash";
} }
if (info_hash.length() != 20 && !fail) {
fail = true;
msg = "bad info hash length " + info_hash.length();
}
if (ip == null && !fail) { if (ip == null && !fail) {
fail = true; fail = true;
msg = "no ip (dest)"; msg = "no ip (dest)";
@ -79,11 +87,22 @@
msg = "no peer id"; msg = "no peer id";
} }
if (peer_id.length() != 20 && !fail) {
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; InfoHash ih = null;
if (!fail) { if (!fail) {
try { try {
ih = new InfoHash(info_hash); ih = torrents.createInfoHash(info_hash);
} catch (Exception e) { } catch (IllegalArgumentException e) {
fail = true; fail = true;
msg = "bad infohash " + e; msg = "bad infohash " + e;
} }
@ -94,7 +113,10 @@
try { try {
if (ip.endsWith(".i2p")) if (ip.endsWith(".i2p"))
ip = ip.substring(0, ip.length() - 4); 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) { } catch (Exception e) {
fail = true; fail = true;
msg = "bad dest " + e; msg = "bad dest " + e;
@ -104,8 +126,8 @@
PID pid = null; PID pid = null;
if (!fail) { if (!fail) {
try { try {
pid = new PID(peer_id); pid = torrents.createPID(peer_id);
} catch (Exception e) { } catch (IllegalArgumentException e) {
fail = true; fail = true;
msg = "bad peer id " + e; msg = "bad peer id " + e;
} }
@ -155,15 +177,14 @@
} catch (NumberFormatException nfe) {}; } catch (NumberFormatException nfe) {};
} }
Torrents torrents = ZzzOTController.getTorrents(); Map<String, Object> m = new HashMap(8);
Map<String, Object> m = new HashMap();
if (fail) { if (fail) {
m.put("failure reason", msg); m.put("failure reason", msg);
} else if ("stopped".equals(event)) { } else if ("stopped".equals(event)) {
Peers peers = torrents.get(ih); Peers peers = torrents.get(ih);
if (matchIP && peers != null) if (matchIP && peers != null)
peers.remove(pid); peers.remove(pid);
m.put("interval", Integer.valueOf(INTERVAL)); m.put("interval", torrents.getInterval());
} else { } else {
Peers peers = torrents.get(ih); Peers peers = torrents.get(ih);
if (peers == null) { if (peers == null) {
@ -188,7 +209,7 @@
if (matchIP) if (matchIP)
p.setLeft(left); p.setLeft(left);
m.put("interval", Integer.valueOf(INTERVAL)); m.put("interval", torrents.getInterval());
int size = peers.size(); int size = peers.size();
int seeds = peers.countSeeds(); int seeds = peers.countSeeds();
m.put("complete", Integer.valueOf(seeds)); m.put("complete", Integer.valueOf(seeds));

View File

@ -1,4 +1,4 @@
<%@page import="net.i2p.zzzot.ZzzOTController" %> <%@page import="net.i2p.zzzot.ZzzOTController,net.i2p.zzzot.Torrents" %>
<html> <html>
<head> <head>
<title>ZzzOT</title> <title>ZzzOT</title>
@ -6,9 +6,20 @@
<p> <p>
zzzot zzzot
<p> <p>
<%
Torrents torrents = ZzzOTController.getTorrents();
if (torrents != null) {
%>
<table cellspacing="8"> <table cellspacing="8">
<tr><td>Torrents:<td align="right"><%=ZzzOTController.getTorrents().size()%> <tr><td>Torrents:<td align="right"><%=torrents.size()%>
<tr><td>Peers:<td align="right"><%=ZzzOTController.getTorrents().countPeers()%> <tr><td>Peers:<td align="right"><%=torrents.countPeers()%>
</table> </table>
<%
} else {
%>
ZzzOT is not running
<%
}
%>
</body> </body>
</html> </html>

View File

@ -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 * Above one-liner is so there is no whitespace -> IllegalStateException
@ -27,6 +27,10 @@
*/ */
// so the chars will turn into bytes correctly // so the chars will turn into bytes correctly
request.setCharacterEncoding("ISO-8859-1"); 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(); java.io.OutputStream cout = response.getOutputStream();
response.setCharacterEncoding("ISO-8859-1"); response.setCharacterEncoding("ISO-8859-1");
response.setContentType("text/plain"); response.setContentType("text/plain");
@ -46,20 +50,24 @@
boolean all = info_hash == null; boolean all = info_hash == null;
Torrents torrents = ZzzOTController.getTorrents();
if (torrents == null && !fail) {
fail = true;
msg = "tracker is down";
}
InfoHash ih = null; InfoHash ih = null;
if ((!all) && !fail) { if ((!all) && !fail) {
try { try {
ih = new InfoHash(info_hash); ih = torrents.createInfoHash(info_hash);
} catch (Exception e) { } catch (Exception e) {
fail = true; fail = true;
msg = "bad infohash " + e; msg = "bad infohash " + e;
} }
} }
Torrents torrents = ZzzOTController.getTorrents();
// build 3-level dictionary // build 3-level dictionary
Map<String, Object> m = new HashMap(); Map<String, Object> m = new HashMap(4);
if (fail) { if (fail) {
m.put("failure reason", msg); m.put("failure reason", msg);
} else { } else {

View File

@ -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) * Copyright 2010 zzz (zzz@mail.i2p)
@ -62,6 +62,10 @@
} else if (req.startsWith("locate dG9ycmVud")) { // locate b64(torrent) } else if (req.startsWith("locate dG9ycmVud")) { // locate b64(torrent)
// all the peers // all the peers
Torrents torrents = ZzzOTController.getTorrents(); Torrents torrents = ZzzOTController.getTorrents();
if (torrents == null) {
response.setStatus(503, "Down");
return;
}
for (InfoHash ihash : torrents.keySet()) { for (InfoHash ihash : torrents.keySet()) {
Peers peers = torrents.get(ihash); Peers peers = torrents.get(ihash);
if (peers == null) if (peers == null)