forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head 5d56a7eb371dddb9336e596bda69f99c91294b05)
to branch 'i2p.i2p.str4d.ui' (head 3aeafcdb5c0ffbc9c77f574558f8438d3e81133e)
This commit is contained in:
@ -404,7 +404,11 @@ trans.fr = installer/resources/locale-man/man_fr.po
|
|||||||
trans.it = installer/resources/locale-man/man_it.po
|
trans.it = installer/resources/locale-man/man_it.po
|
||||||
trans.ko = installer/resources/locale-man/man_ko.po
|
trans.ko = installer/resources/locale-man/man_ko.po
|
||||||
trans.nl = installer/resources/locale-man/man_nl.po
|
trans.nl = installer/resources/locale-man/man_nl.po
|
||||||
|
trans.pl = installer/resources/locale-man/man_pl.po
|
||||||
trans.pt = installer/resources/locale-man/man_pt.po
|
trans.pt = installer/resources/locale-man/man_pt.po
|
||||||
|
trans.pt_BR = installer/resources/locale-man/man_pt_BR.po
|
||||||
|
trans.ru_RU = installer/resources/locale-man/man_ru.po
|
||||||
|
trans.sv_SE = installer/resources/locale-man/man_sv.po
|
||||||
trans.zh_CN = installer/resources/locale-man/man_zh.po
|
trans.zh_CN = installer/resources/locale-man/man_zh.po
|
||||||
|
|
||||||
[main]
|
[main]
|
||||||
|
@ -212,12 +212,11 @@ Applications:
|
|||||||
Zxing 3.3.0:
|
Zxing 3.3.0:
|
||||||
See licenses/LICENSE-Apache2.0.txt
|
See licenses/LICENSE-Apache2.0.txt
|
||||||
|
|
||||||
Jetty 8.1.21.v20160908:
|
Jetty 9.2.21.v20170120:
|
||||||
See licenses/ABOUT-Jetty.html
|
See licenses/ABOUT-Jetty.html
|
||||||
See licenses/NOTICE-Jetty.html
|
See licenses/NOTICE-Jetty.html
|
||||||
See licenses/LICENSE-Apache2.0.txt
|
See licenses/LICENSE-Apache2.0.txt
|
||||||
See licenses/LICENSE-ECLIPSE-1.0.html
|
See licenses/LICENSE-ECLIPSE-1.0.html
|
||||||
See licenses/NOTICE-Commons-Logging.txt
|
|
||||||
|
|
||||||
JRobin 1.6.0-1:
|
JRobin 1.6.0-1:
|
||||||
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
||||||
@ -284,7 +283,7 @@ Applications:
|
|||||||
Bundles systray4j-2.4.1:
|
Bundles systray4j-2.4.1:
|
||||||
See licenses/LICENSE-LGPLv2.1.txt
|
See licenses/LICENSE-LGPLv2.1.txt
|
||||||
|
|
||||||
Tomcat 6.0.48:
|
Tomcat 8.0.33:
|
||||||
Copyright 1999-2016 The Apache Software Foundation
|
Copyright 1999-2016 The Apache Software Foundation
|
||||||
See licenses/LICENSE-Apache2.0.txt
|
See licenses/LICENSE-Apache2.0.txt
|
||||||
See licenses/NOTICE-Tomcat.txt
|
See licenses/NOTICE-Tomcat.txt
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<project name="addressbook" default="war" basedir=".">
|
<project name="addressbook" default="all" basedir=".">
|
||||||
|
|
||||||
<property name="src" value="java/src"/>
|
<property name="src" value="java/src"/>
|
||||||
<property name="build" value="build"/>
|
<property name="build" value="build"/>
|
||||||
@ -9,6 +9,8 @@
|
|||||||
<property name="javac.compilerargs" value="" />
|
<property name="javac.compilerargs" value="" />
|
||||||
<property name="javac.version" value="1.7" />
|
<property name="javac.version" value="1.7" />
|
||||||
|
|
||||||
|
<target name="all" depends="jar, emptyWar"/>
|
||||||
|
|
||||||
<target name="init">
|
<target name="init">
|
||||||
<mkdir dir="${build}"/>
|
<mkdir dir="${build}"/>
|
||||||
<mkdir dir="${dist}"/>
|
<mkdir dir="${dist}"/>
|
||||||
@ -36,24 +38,10 @@
|
|||||||
</depend>
|
</depend>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="dependServlet" if="depend.available">
|
<target name="compile" depends="init, depend, warUpToDate">
|
||||||
<depend
|
|
||||||
cache="../../build"
|
|
||||||
srcdir="${src}"
|
|
||||||
destdir="${build}" >
|
|
||||||
<!-- Depend on classes instead of jars where available -->
|
|
||||||
<classpath>
|
|
||||||
<pathelement location="../../core/java/build/obj" />
|
|
||||||
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
|
|
||||||
</classpath>
|
|
||||||
</depend>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="compile" depends="init, depend">
|
|
||||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||||
includeAntRuntime="false"
|
includeAntRuntime="false"
|
||||||
srcdir="${src}" destdir="${build}"
|
srcdir="${src}" destdir="${build}">
|
||||||
excludes="net/i2p/addressbook/Servlet.java">
|
|
||||||
<compilerarg line="${javac.compilerargs}" />
|
<compilerarg line="${javac.compilerargs}" />
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../../core/java/build/i2p.jar" />
|
<pathelement location="../../core/java/build/i2p.jar" />
|
||||||
@ -61,20 +49,6 @@
|
|||||||
</javac>
|
</javac>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="compileServlet" depends="init, dependServlet, compile">
|
|
||||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
|
||||||
includeAntRuntime="false"
|
|
||||||
srcdir="${src}" destdir="${build}"
|
|
||||||
includes="net/i2p/addressbook/Servlet.java">
|
|
||||||
<compilerarg line="${javac.compilerargs}" />
|
|
||||||
<classpath>
|
|
||||||
<pathelement location="../../core/java/build/i2p.jar" />
|
|
||||||
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
|
|
||||||
</classpath>
|
|
||||||
</javac>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- unused for now (except for Android), as we oddly ship addressbook as a .war -->
|
|
||||||
<target name="jar" depends="compile, changes">
|
<target name="jar" depends="compile, changes">
|
||||||
<!-- set if unset -->
|
<!-- set if unset -->
|
||||||
<property name="workspace.changes.tr" value="" />
|
<property name="workspace.changes.tr" value="" />
|
||||||
@ -92,27 +66,12 @@
|
|||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="war" depends="compileServlet, changes, warUpToDate" unless="war.uptodate">
|
<target name="emptyWar" depends="init">
|
||||||
<mkdir dir="${dist}/tmp"/>
|
<jar destfile="${dist}/${war}" >
|
||||||
<mkdir dir="${dist}/tmp/WEB-INF"/>
|
|
||||||
<mkdir dir="${dist}/tmp/WEB-INF/classes"/>
|
|
||||||
<copy todir="${dist}/tmp/WEB-INF/classes">
|
|
||||||
<fileset dir="${build}"/>
|
|
||||||
</copy>
|
|
||||||
<!-- set if unset -->
|
|
||||||
<property name="workspace.changes.tr" value="" />
|
|
||||||
<war basedir="${dist}/tmp" webxml="web.xml" destfile="${dist}/${war}">
|
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Implementation-Version" value="${full.version}" />
|
<attribute name="Note" value="Intentionally empty" />
|
||||||
<attribute name="Built-By" value="${build.built-by}" />
|
|
||||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
|
||||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
|
||||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
|
||||||
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
|
|
||||||
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</war>
|
</jar>
|
||||||
<delete dir="${dist}/tmp"/>
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="warUpToDate">
|
<target name="warUpToDate">
|
||||||
|
@ -43,13 +43,13 @@ import net.i2p.util.SystemVersion;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Main class of addressbook. Performs updates, and runs the main loop.
|
* Main class of addressbook. Performs updates, and runs the main loop.
|
||||||
|
* As of 0.9.30, package private, run with DaemonThread.
|
||||||
*
|
*
|
||||||
* @author Ragnarok
|
* @author Ragnarok
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Daemon {
|
class Daemon {
|
||||||
public static final String VERSION = "2.0.4";
|
public static final String VERSION = "2.0.4";
|
||||||
private static final Daemon _instance = new Daemon();
|
|
||||||
private volatile boolean _running;
|
private volatile boolean _running;
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
private static final String DEFAULT_SUB = "http://i2p-projekt.i2p/hosts.txt";
|
private static final String DEFAULT_SUB = "http://i2p-projekt.i2p/hosts.txt";
|
||||||
@ -787,14 +787,15 @@ public class Daemon {
|
|||||||
* others are ignored.
|
* others are ignored.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
Daemon daemon = new Daemon();
|
||||||
if (args != null && args.length > 0 && args[0].equals("test"))
|
if (args != null && args.length > 0 && args[0].equals("test"))
|
||||||
_instance.test(args);
|
daemon.test(args);
|
||||||
else
|
else
|
||||||
_instance.run(args);
|
daemon.run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.9.26 */
|
/** @since 0.9.26 */
|
||||||
private static void test(String[] args) {
|
public static void test(String[] args) {
|
||||||
Properties ctxProps = new Properties();
|
Properties ctxProps = new Properties();
|
||||||
String PROP_FORCE = "i2p.naming.blockfile.writeInAppContext";
|
String PROP_FORCE = "i2p.naming.blockfile.writeInAppContext";
|
||||||
ctxProps.setProperty(PROP_FORCE, "true");
|
ctxProps.setProperty(PROP_FORCE, "true");
|
||||||
@ -875,14 +876,14 @@ public class Daemon {
|
|||||||
* Call this to get the addressbook to reread its config and
|
* Call this to get the addressbook to reread its config and
|
||||||
* refetch its subscriptions.
|
* refetch its subscriptions.
|
||||||
*/
|
*/
|
||||||
public static void wakeup() {
|
public void wakeup() {
|
||||||
synchronized (_instance) {
|
synchronized (this) {
|
||||||
_instance.notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stop() {
|
public void stop() {
|
||||||
_instance._running = false;
|
_running = false;
|
||||||
wakeup();
|
wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import net.i2p.util.I2PAppThread;
|
|||||||
public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
||||||
|
|
||||||
private final String[] args;
|
private final String[] args;
|
||||||
|
private final Daemon daemon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a DaemonThread with the command line arguments args.
|
* Construct a DaemonThread with the command line arguments args.
|
||||||
@ -44,6 +45,7 @@ public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
|||||||
*/
|
*/
|
||||||
public DaemonThread(String[] args) {
|
public DaemonThread(String[] args) {
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
daemon = new Daemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@ -56,18 +58,28 @@ public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
|||||||
//} catch (InterruptedException exp) {
|
//} catch (InterruptedException exp) {
|
||||||
//}
|
//}
|
||||||
I2PAppContext.getGlobalContext().namingService().registerUpdater(this);
|
I2PAppContext.getGlobalContext().namingService().registerUpdater(this);
|
||||||
Daemon.main(this.args);
|
try {
|
||||||
|
if (args != null && args.length > 0 && args[0].equals("test"))
|
||||||
|
daemon.test(args);
|
||||||
|
else
|
||||||
|
daemon.run(args);
|
||||||
|
} finally {
|
||||||
I2PAppContext.getGlobalContext().namingService().unregisterUpdater(this);
|
I2PAppContext.getGlobalContext().namingService().unregisterUpdater(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void halt() {
|
public void halt() {
|
||||||
Daemon.stop();
|
daemon.stop();
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The NamingServiceUpdater interface
|
* The NamingServiceUpdater interface.
|
||||||
* @param options ignored
|
* While this may be called directly, the recommended way
|
||||||
|
* is to call I2PAppContext.namingService().requestUpdate(Properties)
|
||||||
|
* which will call this.
|
||||||
|
*
|
||||||
|
* @param options ignored, may be null
|
||||||
* @since 0.8.7
|
* @since 0.8.7
|
||||||
*/
|
*/
|
||||||
public void update(Properties options) {
|
public void update(Properties options) {
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE web-app
|
|
||||||
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
|
|
||||||
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
|
|
||||||
|
|
||||||
<web-app>
|
|
||||||
<filter>
|
|
||||||
<filter-name>XSSFilter</filter-name>
|
|
||||||
<filter-class>net.i2p.servlet.filters.XSSFilter</filter-class>
|
|
||||||
</filter>
|
|
||||||
<filter-mapping>
|
|
||||||
<filter-name>XSSFilter</filter-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</filter-mapping>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>addressbook</servlet-name>
|
|
||||||
<servlet-class>net.i2p.addressbook.Servlet</servlet-class>
|
|
||||||
<init-param>
|
|
||||||
<param-name>home</param-name>
|
|
||||||
<param-value>./addressbook</param-value>
|
|
||||||
</init-param>
|
|
||||||
<load-on-startup>1</load-on-startup>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>addressbook</servlet-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
|
|
||||||
<!-- this webapp doesn't actually use sessions or cookies -->
|
|
||||||
<session-config>
|
|
||||||
<session-timeout>30</session-timeout>
|
|
||||||
<cookie-config>
|
|
||||||
<http-only>true</http-only>
|
|
||||||
</cookie-config>
|
|
||||||
</session-config>
|
|
||||||
</web-app>
|
|
@ -70,6 +70,7 @@ public class I2PSnarkUtil {
|
|||||||
private boolean _areFilesPublic;
|
private boolean _areFilesPublic;
|
||||||
private List<String> _openTrackers;
|
private List<String> _openTrackers;
|
||||||
private DHT _dht;
|
private DHT _dht;
|
||||||
|
private long _startedTime;
|
||||||
|
|
||||||
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
|
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
|
||||||
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
|
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
|
||||||
@ -260,6 +261,8 @@ public class I2PSnarkUtil {
|
|||||||
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
|
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
|
||||||
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
|
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
|
||||||
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
||||||
|
if (_manager != null)
|
||||||
|
_startedTime = _context.clock().now();
|
||||||
_connecting = false;
|
_connecting = false;
|
||||||
}
|
}
|
||||||
if (_shouldUseDHT && _manager != null && _dht == null)
|
if (_shouldUseDHT && _manager != null && _dht == null)
|
||||||
@ -295,6 +298,7 @@ public class I2PSnarkUtil {
|
|||||||
_dht.stop();
|
_dht.stop();
|
||||||
_dht = null;
|
_dht = null;
|
||||||
}
|
}
|
||||||
|
_startedTime = 0;
|
||||||
I2PSocketManager mgr = _manager;
|
I2PSocketManager mgr = _manager;
|
||||||
// FIXME this can cause race NPEs elsewhere
|
// FIXME this can cause race NPEs elsewhere
|
||||||
_manager = null;
|
_manager = null;
|
||||||
@ -310,6 +314,16 @@ public class I2PSnarkUtil {
|
|||||||
_tmpDir.mkdirs();
|
_tmpDir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When did we connect to the network?
|
||||||
|
* For RPC
|
||||||
|
* @return 0 if not connected
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public long getStartedTime() {
|
||||||
|
return _startedTime;
|
||||||
|
}
|
||||||
|
|
||||||
/** connect to the given destination */
|
/** connect to the given destination */
|
||||||
I2PSocket connect(PeerID peer) throws IOException {
|
I2PSocket connect(PeerID peer) throws IOException {
|
||||||
I2PSocketManager mgr = _manager;
|
I2PSocketManager mgr = _manager;
|
||||||
|
@ -89,6 +89,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
*/
|
*/
|
||||||
//private static final long OPTION_AZMP = 0x1000000000000000l;
|
//private static final long OPTION_AZMP = 0x1000000000000000l;
|
||||||
private long options;
|
private long options;
|
||||||
|
private final boolean _isIncoming;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Outgoing connection.
|
* Outgoing connection.
|
||||||
@ -103,6 +104,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
this.infohash = infohash;
|
this.infohash = infohash;
|
||||||
this.metainfo = metainfo;
|
this.metainfo = metainfo;
|
||||||
_id = __id.incrementAndGet();
|
_id = __id.incrementAndGet();
|
||||||
|
_isIncoming = false;
|
||||||
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
|
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +132,16 @@ public class Peer implements Comparable<Peer>
|
|||||||
_id = __id.incrementAndGet();
|
_id = __id.incrementAndGet();
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
|
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
|
||||||
|
_isIncoming = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an incoming connection?
|
||||||
|
* For RPC
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public boolean isIncoming() {
|
||||||
|
return _isIncoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +28,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.client.streaming.I2PServerSocket;
|
import net.i2p.client.streaming.I2PServerSocket;
|
||||||
@ -237,8 +238,10 @@ public class Snark
|
|||||||
private volatile boolean _autoStoppable;
|
private volatile boolean _autoStoppable;
|
||||||
// String indicating main activity
|
// String indicating main activity
|
||||||
private volatile String activity = "Not started";
|
private volatile String activity = "Not started";
|
||||||
private final long savedUploaded;
|
private long savedUploaded;
|
||||||
|
private long _startedTime;
|
||||||
|
private static final AtomicInteger __RPCID = new AtomicInteger();
|
||||||
|
private final int _rpcID = __RPCID.incrementAndGet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* from main() via parseArguments() single torrent
|
* from main() via parseArguments() single torrent
|
||||||
@ -542,6 +545,7 @@ public class Snark
|
|||||||
starting = true;
|
starting = true;
|
||||||
try {
|
try {
|
||||||
x_startTorrent();
|
x_startTorrent();
|
||||||
|
_startedTime = _util.getContext().clock().now();
|
||||||
} finally {
|
} finally {
|
||||||
starting = false;
|
starting = false;
|
||||||
}
|
}
|
||||||
@ -633,16 +637,17 @@ public class Snark
|
|||||||
if (st != null) {
|
if (st != null) {
|
||||||
// TODO: Cache the config-in-mem to compare vs config-on-disk
|
// TODO: Cache the config-in-mem to compare vs config-on-disk
|
||||||
// (needed for auto-save to not double-save in some cases)
|
// (needed for auto-save to not double-save in some cases)
|
||||||
//boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
|
long nowUploaded = getUploaded();
|
||||||
boolean changed = true;
|
boolean changed = storage.isChanged() || nowUploaded != savedUploaded;
|
||||||
if (changed && completeListener != null)
|
|
||||||
completeListener.updateStatus(this);
|
|
||||||
try {
|
try {
|
||||||
storage.close();
|
storage.close();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
System.out.println("Error closing " + torrent);
|
System.out.println("Error closing " + torrent);
|
||||||
ioe.printStackTrace();
|
ioe.printStackTrace();
|
||||||
}
|
}
|
||||||
|
savedUploaded = nowUploaded;
|
||||||
|
if (changed && completeListener != null)
|
||||||
|
completeListener.updateStatus(this);
|
||||||
}
|
}
|
||||||
if (fast)
|
if (fast)
|
||||||
// HACK: See above if(!fast)
|
// HACK: See above if(!fast)
|
||||||
@ -1285,8 +1290,12 @@ public class Snark
|
|||||||
|
|
||||||
allChecked = true;
|
allChecked = true;
|
||||||
checking = false;
|
checking = false;
|
||||||
if (storage.isChanged() && completeListener != null)
|
if (storage.isChanged() && completeListener != null) {
|
||||||
completeListener.updateStatus(this);
|
completeListener.updateStatus(this);
|
||||||
|
// this saved the status, so reset the variables
|
||||||
|
storage.clearChanged();
|
||||||
|
savedUploaded = getUploaded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void storageCompleted(Storage storage)
|
public void storageCompleted(Storage storage)
|
||||||
@ -1295,8 +1304,12 @@ public class Snark
|
|||||||
_log.info("Completely received " + torrent);
|
_log.info("Completely received " + torrent);
|
||||||
//storage.close();
|
//storage.close();
|
||||||
//System.out.println("Completely received: " + torrent);
|
//System.out.println("Completely received: " + torrent);
|
||||||
if (completeListener != null)
|
if (completeListener != null) {
|
||||||
completeListener.torrentComplete(this);
|
completeListener.torrentComplete(this);
|
||||||
|
// this saved the status, so reset the variables
|
||||||
|
savedUploaded = getUploaded();
|
||||||
|
storage.clearChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWantedPieces(Storage storage)
|
public void setWantedPieces(Storage storage)
|
||||||
@ -1364,4 +1377,23 @@ public class Snark
|
|||||||
long limit = 1024l * _util.getMaxUpBW();
|
long limit = 1024l * _util.getMaxUpBW();
|
||||||
return total > limit;
|
return total > limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique ID for this torrent, useful for RPC
|
||||||
|
* @return positive value unless you wrap around
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public int getRPCID() {
|
||||||
|
return _rpcID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When did we start this torrent
|
||||||
|
* For RPC
|
||||||
|
* @return 0 if not started before. Not cleared when stopped.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public long getStartedTime() {
|
||||||
|
return _startedTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.app.ClientApp;
|
||||||
import net.i2p.app.ClientAppManager;
|
import net.i2p.app.ClientAppManager;
|
||||||
|
import net.i2p.app.ClientAppState;
|
||||||
import net.i2p.crypto.SHA1Hash;
|
import net.i2p.crypto.SHA1Hash;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
@ -51,7 +53,7 @@ import org.klomp.snark.dht.KRPC;
|
|||||||
/**
|
/**
|
||||||
* Manage multiple snarks
|
* Manage multiple snarks
|
||||||
*/
|
*/
|
||||||
public class SnarkManager implements CompleteListener {
|
public class SnarkManager implements CompleteListener, ClientApp {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of (canonical) filename of the .torrent file to Snark instance.
|
* Map of (canonical) filename of the .torrent file to Snark instance.
|
||||||
@ -246,6 +248,13 @@ public class SnarkManager implements CompleteListener {
|
|||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
_running = true;
|
_running = true;
|
||||||
|
if ("i2psnark".equals(_contextName)) {
|
||||||
|
// Register with the ClientAppManager so the rpc plugin can find us
|
||||||
|
// only if default instance
|
||||||
|
ClientAppManager cmgr = _context.clientAppManager();
|
||||||
|
if (cmgr != null)
|
||||||
|
cmgr.register(this);
|
||||||
|
}
|
||||||
_peerCoordinatorSet = new PeerCoordinatorSet();
|
_peerCoordinatorSet = new PeerCoordinatorSet();
|
||||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||||
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
||||||
@ -315,6 +324,12 @@ public class SnarkManager implements CompleteListener {
|
|||||||
_connectionAcceptor.halt();
|
_connectionAcceptor.halt();
|
||||||
_idleChecker.cancel();
|
_idleChecker.cancel();
|
||||||
stopAllTorrents(true);
|
stopAllTorrents(true);
|
||||||
|
if ("i2psnark".equals(_contextName)) {
|
||||||
|
// only if default instance
|
||||||
|
ClientAppManager cmgr = _context.clientAppManager();
|
||||||
|
if (cmgr != null)
|
||||||
|
cmgr.unregister(this);
|
||||||
|
}
|
||||||
if (_log.shouldWarn())
|
if (_log.shouldWarn())
|
||||||
_log.warn("Snark stop() end");
|
_log.warn("Snark stop() end");
|
||||||
}
|
}
|
||||||
@ -322,6 +337,46 @@ public class SnarkManager implements CompleteListener {
|
|||||||
/** @since 0.9.1 */
|
/** @since 0.9.1 */
|
||||||
public boolean isStopping() { return _stopping; }
|
public boolean isStopping() { return _stopping; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp method. Does nothing.
|
||||||
|
* Doesn't matter, we are only registering.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void startup() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp method. Does nothing.
|
||||||
|
* Doesn't matter, we are only registering.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void shutdown(String[] args) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp method.
|
||||||
|
* Doesn't matter, we are only registering.
|
||||||
|
* @return INITIALIZED always.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public ClientAppState getState() {
|
||||||
|
return ClientAppState.INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp method.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return "i2psnark";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientApp method.
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "i2psnark: " + _contextPath;
|
||||||
|
}
|
||||||
|
|
||||||
/** hook to I2PSnarkUtil for the servlet */
|
/** hook to I2PSnarkUtil for the servlet */
|
||||||
public I2PSnarkUtil util() { return _util; }
|
public I2PSnarkUtil util() { return _util; }
|
||||||
|
|
||||||
@ -440,6 +495,14 @@ public class SnarkManager implements CompleteListener {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For RPC
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public File getConfigDir() {
|
||||||
|
return _configDir;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate the old flat config file to the new config dir
|
* Migrate the old flat config file to the new config dir
|
||||||
* containing the config file minus the per-torrent entries,
|
* containing the config file minus the per-torrent entries,
|
||||||
@ -1526,9 +1589,9 @@ public class SnarkManager implements CompleteListener {
|
|||||||
* Called from servlet. This is only for the 'create torrent' form.
|
* Called from servlet. This is only for the 'create torrent' form.
|
||||||
*
|
*
|
||||||
* @param metainfo the metainfo for the torrent
|
* @param metainfo the metainfo for the torrent
|
||||||
* @param bitfield the current completion status of the torrent
|
* @param bitfield the current completion status of the torrent, or null
|
||||||
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent", which is also the name of the torrent
|
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent", which is also the name of the torrent
|
||||||
* Must be a filesystem-safe name.
|
* Must be a filesystem-safe name. If null, will generate a name from the metainfo.
|
||||||
* @param baseFile may be null, if so look in rootDataDir
|
* @param baseFile may be null, if so look in rootDataDir
|
||||||
* @throws RuntimeException via Snark.fatal()
|
* @throws RuntimeException via Snark.fatal()
|
||||||
* @return success
|
* @return success
|
||||||
@ -1542,10 +1605,18 @@ public class SnarkManager implements CompleteListener {
|
|||||||
if (snark != null) {
|
if (snark != null) {
|
||||||
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else if (bitfield != null) {
|
||||||
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
|
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
|
||||||
}
|
}
|
||||||
// so addTorrent won't recheck
|
// so addTorrent won't recheck
|
||||||
|
if (filename == null) {
|
||||||
|
File f = new File(getDataDir(), Storage.filterName(metainfo.getName()) + ".torrent");
|
||||||
|
if (f.exists()) {
|
||||||
|
addMessage(_t("Failed to copy torrent file to {0}", f.getAbsolutePath()));
|
||||||
|
_log.error("Torrent file already exists: " + f);
|
||||||
|
}
|
||||||
|
filename = f.getAbsolutePath();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
|
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
|
||||||
// hold the lock for a long time
|
// hold the lock for a long time
|
||||||
|
@ -305,6 +305,14 @@ public class Storage implements Closeable
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the storage changed variable
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
void clearChanged() {
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File checking in progress.
|
* File checking in progress.
|
||||||
* @since 0.9.3
|
* @since 0.9.3
|
||||||
|
@ -106,11 +106,11 @@ class NodeInfo extends SimpleDataStructure {
|
|||||||
if (parts.length != 4)
|
if (parts.length != 4)
|
||||||
throw new DataFormatException("Bad format");
|
throw new DataFormatException("Bad format");
|
||||||
byte[] nid = Base64.decode(parts[0]);
|
byte[] nid = Base64.decode(parts[0]);
|
||||||
if (nid == null)
|
if (nid == null || nid.length != NID.HASH_LENGTH)
|
||||||
throw new DataFormatException("Bad NID");
|
throw new DataFormatException("Bad NID");
|
||||||
nID = new NID(nid);
|
nID = new NID(nid);
|
||||||
byte[] h = Base64.decode(parts[1]);
|
byte[] h = Base64.decode(parts[1]);
|
||||||
if (h == null)
|
if (h == null || h.length != Hash.HASH_LENGTH)
|
||||||
throw new DataFormatException("Bad hash");
|
throw new DataFormatException("Bad hash");
|
||||||
//hash = new Hash(h);
|
//hash = new Hash(h);
|
||||||
hash = Hash.create(h);
|
hash = Hash.create(h);
|
||||||
|
@ -1803,6 +1803,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
|||||||
client = "Vuze" + getAzVersion(pid.getID());
|
client = "Vuze" + getAzVersion(pid.getID());
|
||||||
else if ("CwsL".equals(ch))
|
else if ("CwsL".equals(ch))
|
||||||
client = "I2PSnarkXL";
|
client = "I2PSnarkXL";
|
||||||
|
else if ("LVhE".equals(ch))
|
||||||
|
client = "XD" + getAzVersion(pid.getID());
|
||||||
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
|
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
|
||||||
client = "Robert" + getRobtVersion(pid.getID());
|
client = "Robert" + getRobtVersion(pid.getID());
|
||||||
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
||||||
|
@ -22,15 +22,24 @@
|
|||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
<Call name="addConnector">
|
<Call name="addConnector">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
|
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||||
|
<Arg><Ref id="Server" /></Arg>
|
||||||
|
<Arg type="int">1</Arg> <!-- number of acceptors -->
|
||||||
|
<Arg type="int">0</Arg> <!-- default number of selectors -->
|
||||||
|
<Arg>
|
||||||
|
<Array type="org.eclipse.jetty.server.ConnectionFactory"> <!-- varargs so we need an array -->
|
||||||
|
<Item>
|
||||||
|
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.server.HttpConfiguration" />
|
||||||
|
</Arg>
|
||||||
|
</New>
|
||||||
|
</Item>
|
||||||
|
</Array>
|
||||||
|
</Arg>
|
||||||
<Set name="host">127.0.0.1</Set>
|
<Set name="host">127.0.0.1</Set>
|
||||||
<Set name="port">8002</Set>
|
<Set name="port">8002</Set>
|
||||||
<Set name="maxIdleTime">600000</Set>
|
<Set name="idleTimeout">600000</Set>
|
||||||
<Set name="Acceptors">1</Set>
|
|
||||||
<Set name="statsOn">false</Set>
|
|
||||||
<Set name="lowResourcesConnections">5000</Set>
|
|
||||||
<Set name="lowResourcesMaxIdleTime">5000</Set>
|
|
||||||
<Set name="useDirectBuffers">false</Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
@ -96,7 +105,7 @@
|
|||||||
<Ref id="DeploymentManager">
|
<Ref id="DeploymentManager">
|
||||||
<Call name="addAppProvider">
|
<Call name="addAppProvider">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.deploy.providers.ContextProvider">
|
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||||
<Set name="monitoredDirName">./contexts</Set>
|
<Set name="monitoredDirName">./contexts</Set>
|
||||||
<Set name="scanInterval">0</Set>
|
<Set name="scanInterval">0</Set>
|
||||||
</New>
|
</New>
|
||||||
|
@ -4,9 +4,24 @@ java -jar i2psnark.jar
|
|||||||
|
|
||||||
I2PSnark web ui will be at http://127.0.0.1:8002/i2psnark/
|
I2PSnark web ui will be at http://127.0.0.1:8002/i2psnark/
|
||||||
|
|
||||||
Please note that http://127.0.0.1:8002/ will 404, to be fixed
|
|
||||||
|
|
||||||
I2PSnark is GPL'ed software, based on Snark (http://www.klomp.org/) to run on top of I2P
|
I2PSnark is GPL'ed software, based on Snark (http://www.klomp.org/) to run on top of I2P
|
||||||
(https://geti2p.net/) within a webserver (such as the bundled Jetty from
|
(https://geti2p.net/) within a webserver (such as the bundled Jetty from
|
||||||
https://www.eclipse.org/jetty/). For more information about I2PSnark, get in touch
|
https://www.eclipse.org/jetty/). For more information about I2PSnark, get in touch
|
||||||
with the folks at http://forum.i2p2.de/
|
with the folks at http://forum.i2p2.de/
|
||||||
|
|
||||||
|
|
||||||
|
To add RPC support:
|
||||||
|
|
||||||
|
1) Stop i2psnark standalone if running.
|
||||||
|
|
||||||
|
2a) If you have the i2psnark-rpc plugin installed in your router already,
|
||||||
|
copy the file ~/.i2p/plugins/i2psnark-rpc/console/webapps/transmission.war
|
||||||
|
to the webapps/ directory in your standalone install.
|
||||||
|
|
||||||
|
2b) If you do not have the i2psnark-rpc plugin installed, get the i2p.plugins.i2psnark-rpc
|
||||||
|
branch out of monotone, build with 'ant war', and copy the file src/build/transmission.war.jar
|
||||||
|
to the file webapps/transmission.war in your standalone install.
|
||||||
|
|
||||||
|
3) Start i2psnark standalone as usual. The transmission web interface will be at
|
||||||
|
http://127.0.0.1:8002/transmission/web/ or if you have transmission-remote installed,
|
||||||
|
test with 'transmission-remote 8002 -l'
|
||||||
|
@ -277,14 +277,17 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<!-- jsp-api.jar only present for debian builds -->
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<!-- tomcat-api.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||||
<!-- jasper-el.jar only present for debian builds -->
|
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||||
|
|
||||||
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||||
<pathelement location="build/i2ptunnel.jar" />
|
<pathelement location="build/i2ptunnel.jar" />
|
||||||
<pathelement location="build/temp-beans.jar" />
|
<pathelement location="build/temp-beans.jar" />
|
||||||
@ -309,12 +312,14 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<!-- jsp-api.jar only present for debian builds -->
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<!-- tomcat-api.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||||
<!-- jasper-el.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||||
|
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
<pathelement location="build/i2ptunnel.jar" />
|
<pathelement location="build/i2ptunnel.jar" />
|
||||||
|
@ -313,8 +313,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a subsession to a shared client if necessary.
|
* Add a DSA_SHA1 subsession to the shared client if necessary.
|
||||||
*
|
*
|
||||||
|
* @return subsession, or null if none was added
|
||||||
* @since 0.9.20
|
* @since 0.9.20
|
||||||
*/
|
*/
|
||||||
protected static synchronized I2PSession addSubsession(I2PTunnel tunnel) {
|
protected static synchronized I2PSession addSubsession(I2PTunnel tunnel) {
|
||||||
|
@ -204,7 +204,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
"Proxy-Connection: close\r\n"+
|
"Proxy-Connection: close\r\n"+
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: SSL to I2P address rejected</H1>" +
|
"<html><body><H1>I2P ERROR: SSL to I2P address rejected</H1>" +
|
||||||
"SSL for to .i2p addresses denied by configuration." +
|
"SSL to .i2p addresses denied by configuration." +
|
||||||
"You may change the configuration in I2PTunnel";
|
"You may change the configuration in I2PTunnel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,13 +210,13 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
|||||||
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
|
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.reset();
|
||||||
} catch (IOException ioe) {}
|
} catch (IOException ioe) {}
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Error while receiving the new IRC Connection", ex);
|
_log.warn("Error while receiving the new IRC Connection", ex);
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.reset();
|
||||||
} catch (IOException ioe) {}
|
} catch (IOException ioe) {}
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (_log.shouldLog(Log.ERROR))
|
||||||
_log.error("OOM in IRC server", oom);
|
_log.error("OOM in IRC server", oom);
|
||||||
|
@ -18,6 +18,7 @@ import java.net.SocketException;
|
|||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -29,12 +30,14 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
import net.i2p.I2PException;
|
import net.i2p.I2PException;
|
||||||
|
import net.i2p.client.I2PClient;
|
||||||
import net.i2p.client.I2PSession;
|
import net.i2p.client.I2PSession;
|
||||||
import net.i2p.client.I2PSessionException;
|
import net.i2p.client.I2PSessionException;
|
||||||
import net.i2p.client.streaming.I2PServerSocket;
|
import net.i2p.client.streaming.I2PServerSocket;
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
import net.i2p.client.streaming.I2PSocketManager;
|
import net.i2p.client.streaming.I2PSocketManager;
|
||||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.util.EventDispatcher;
|
import net.i2p.util.EventDispatcher;
|
||||||
@ -67,6 +70,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
private static final boolean DEFAULT_USE_POOL = true;
|
private static final boolean DEFAULT_USE_POOL = true;
|
||||||
public static final String PROP_USE_SSL = "useSSL";
|
public static final String PROP_USE_SSL = "useSSL";
|
||||||
public static final String PROP_UNIQUE_LOCAL = "enableUniqueLocal";
|
public static final String PROP_UNIQUE_LOCAL = "enableUniqueLocal";
|
||||||
|
/** @since 0.9.30 */
|
||||||
|
public static final String PROP_ALT_PKF = "altPrivKeyFile";
|
||||||
/** apparently unused */
|
/** apparently unused */
|
||||||
protected static volatile long __serverId = 0;
|
protected static volatile long __serverId = 0;
|
||||||
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
|
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
|
||||||
@ -217,6 +222,9 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
portNum, props);
|
portNum, props);
|
||||||
rv.setName("I2PTunnel Server");
|
rv.setName("I2PTunnel Server");
|
||||||
getTunnel().addSession(rv.getSession());
|
getTunnel().addSession(rv.getSession());
|
||||||
|
String alt = props.getProperty(PROP_ALT_PKF);
|
||||||
|
if (alt != null)
|
||||||
|
addSubsession(rv, alt);
|
||||||
return rv;
|
return rv;
|
||||||
} catch (I2PSessionException ise) {
|
} catch (I2PSessionException ise) {
|
||||||
throw new IllegalArgumentException("Can't create socket manager", ise);
|
throw new IllegalArgumentException("Can't create socket manager", ise);
|
||||||
@ -225,6 +233,44 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a non-DSA_SHA1 subsession to the DSA_SHA1 server if necessary.
|
||||||
|
*
|
||||||
|
* @return subsession, or null if none was added
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
private I2PSession addSubsession(I2PSocketManager sMgr, String alt) {
|
||||||
|
File altFile = TunnelController.filenameToFile(alt);
|
||||||
|
if (alt == null)
|
||||||
|
return null;
|
||||||
|
I2PSession sess = sMgr.getSession();
|
||||||
|
if (sess.getMyDestination().getSigType() != SigType.DSA_SHA1)
|
||||||
|
return null;
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.putAll(getTunnel().getClientOptions());
|
||||||
|
// fixme get actual sig type
|
||||||
|
String name = props.getProperty("inbound.nickname");
|
||||||
|
if (name != null)
|
||||||
|
props.setProperty("inbound.nickname", name + " (EdDSA)");
|
||||||
|
name = props.getProperty("outbound.nickname");
|
||||||
|
if (name != null)
|
||||||
|
props.setProperty("outbound.nickname", name + " (EdDSA)");
|
||||||
|
props.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
|
||||||
|
FileInputStream privData = null;
|
||||||
|
try {
|
||||||
|
privData = new FileInputStream(altFile);
|
||||||
|
return sMgr.addSubsession(privData, props);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
_log.error("Failed to add subssession", ioe);
|
||||||
|
return null;
|
||||||
|
} catch (I2PSessionException ise) {
|
||||||
|
_log.error("Failed to add subssession", ise);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (privData != null) try { privData.close(); } catch (IOException ioe) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Warning, blocks while connecting to router and building tunnels;
|
* Warning, blocks while connecting to router and building tunnels;
|
||||||
@ -238,6 +284,22 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
while (sockMgr.getSession().isClosed()) {
|
while (sockMgr.getSession().isClosed()) {
|
||||||
try {
|
try {
|
||||||
sockMgr.getSession().connect();
|
sockMgr.getSession().connect();
|
||||||
|
// Now connect the subsessions, if any
|
||||||
|
List<I2PSession> subs = sockMgr.getSubsessions();
|
||||||
|
if (!subs.isEmpty()) {
|
||||||
|
for (I2PSession sub : subs) {
|
||||||
|
try {
|
||||||
|
sub.connect();
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("Connected subsession " + sub);
|
||||||
|
} catch (I2PSessionException ise) {
|
||||||
|
// not fatal?
|
||||||
|
String msg = "Unable to connect subsession " + sub;
|
||||||
|
this.l.log(msg);
|
||||||
|
_log.error(msg, ise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (I2PSessionException ise) {
|
} catch (I2PSessionException ise) {
|
||||||
// try to make this error sensible as it will happen...
|
// try to make this error sensible as it will happen...
|
||||||
String portNum = getTunnel().port;
|
String portNum = getTunnel().port;
|
||||||
@ -618,7 +680,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||||
} catch (SocketException ex) {
|
} catch (SocketException ex) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.reset();
|
||||||
} catch (IOException ioe) {}
|
} catch (IOException ioe) {}
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (_log.shouldLog(Log.ERROR))
|
||||||
_log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
|
_log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
|
||||||
|
@ -3,6 +3,7 @@ package net.i2p.i2ptunnel;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -16,12 +17,22 @@ import net.i2p.I2PException;
|
|||||||
import net.i2p.client.I2PClient;
|
import net.i2p.client.I2PClient;
|
||||||
import net.i2p.client.I2PClientFactory;
|
import net.i2p.client.I2PClientFactory;
|
||||||
import net.i2p.client.I2PSession;
|
import net.i2p.client.I2PSession;
|
||||||
|
import net.i2p.client.I2PSessionException;
|
||||||
|
import net.i2p.crypto.KeyGenerator;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
|
import net.i2p.data.KeyCertificate;
|
||||||
|
import net.i2p.data.PrivateKey;
|
||||||
|
import net.i2p.data.PrivateKeyFile;
|
||||||
|
import net.i2p.data.PublicKey;
|
||||||
|
import net.i2p.data.SigningPrivateKey;
|
||||||
|
import net.i2p.data.SigningPublicKey;
|
||||||
|
import net.i2p.data.SimpleDataStructure;
|
||||||
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
|
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
|
||||||
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.util.RandomSource;
|
||||||
import net.i2p.util.SecureFile;
|
import net.i2p.util.SecureFile;
|
||||||
import net.i2p.util.SecureFileOutputStream;
|
import net.i2p.util.SecureFileOutputStream;
|
||||||
import net.i2p.util.SystemVersion;
|
import net.i2p.util.SystemVersion;
|
||||||
@ -83,6 +94,8 @@ public class TunnelController implements Logging {
|
|||||||
private static final String OPT_TAGS_SEND = PFX_OPTION + "crypto.tagsToSend";
|
private static final String OPT_TAGS_SEND = PFX_OPTION + "crypto.tagsToSend";
|
||||||
private static final String OPT_LOW_TAGS = PFX_OPTION + "crypto.lowTagThreshold";
|
private static final String OPT_LOW_TAGS = PFX_OPTION + "crypto.lowTagThreshold";
|
||||||
private static final String OPT_SIG_TYPE = PFX_OPTION + I2PClient.PROP_SIGTYPE;
|
private static final String OPT_SIG_TYPE = PFX_OPTION + I2PClient.PROP_SIGTYPE;
|
||||||
|
/** @since 0.9.30 */
|
||||||
|
private static final String OPT_ALT_PKF = PFX_OPTION + I2PTunnelServer.PROP_ALT_PKF;
|
||||||
|
|
||||||
/** all of these @since 0.9.14 */
|
/** all of these @since 0.9.14 */
|
||||||
public static final String TYPE_CONNECT = "connectclient";
|
public static final String TYPE_CONNECT = "connectclient";
|
||||||
@ -106,7 +119,7 @@ public class TunnelController implements Logging {
|
|||||||
*/
|
*/
|
||||||
public static final SigType PREFERRED_SIGTYPE;
|
public static final SigType PREFERRED_SIGTYPE;
|
||||||
static {
|
static {
|
||||||
if (SystemVersion.isARM() || SystemVersion.isGNU() || SystemVersion.isAndroid()) {
|
if (SystemVersion.isGNU() || SystemVersion.isAndroid()) {
|
||||||
if (SigType.ECDSA_SHA256_P256.isAvailable())
|
if (SigType.ECDSA_SHA256_P256.isAvailable())
|
||||||
PREFERRED_SIGTYPE = SigType.ECDSA_SHA256_P256;
|
PREFERRED_SIGTYPE = SigType.ECDSA_SHA256_P256;
|
||||||
else
|
else
|
||||||
@ -146,8 +159,13 @@ public class TunnelController implements Logging {
|
|||||||
setConfig(config, prefix);
|
setConfig(config, prefix);
|
||||||
_messages = new ArrayList<String>(4);
|
_messages = new ArrayList<String>(4);
|
||||||
boolean keyOK = true;
|
boolean keyOK = true;
|
||||||
if (createKey && (getType().endsWith("server") || getPersistentClientKey()))
|
if (createKey && (!isClient() || getPersistentClientKey())) {
|
||||||
keyOK = createPrivateKey();
|
keyOK = createPrivateKey();
|
||||||
|
if (keyOK && !isClient() && !getType().equals(TYPE_STREAMR_SERVER)) {
|
||||||
|
// check rv?
|
||||||
|
createAltPrivateKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
|
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +204,7 @@ public class TunnelController implements Logging {
|
|||||||
String destStr = dest.toBase64();
|
String destStr = dest.toBase64();
|
||||||
log("Private key created and saved in " + keyFile.getAbsolutePath());
|
log("Private key created and saved in " + keyFile.getAbsolutePath());
|
||||||
log("You should backup this file in a secure place.");
|
log("You should backup this file in a secure place.");
|
||||||
log("New destination: " + destStr);
|
log("New alternate destination: " + destStr);
|
||||||
String b32 = dest.toBase32();
|
String b32 = dest.toBase32();
|
||||||
log("Base32: " + b32);
|
log("Base32: " + b32);
|
||||||
File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR);
|
File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR);
|
||||||
@ -214,6 +232,101 @@ public class TunnelController implements Logging {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates alternate Destination with the same encryption keys as the primary Destination,
|
||||||
|
* but a different signing key.
|
||||||
|
*
|
||||||
|
* Must have already called createPrivateKey() successfully.
|
||||||
|
* Does nothing unless option OPT_ALT_PKF is set with the privkey file name.
|
||||||
|
* Does nothing if the file already exists.
|
||||||
|
*
|
||||||
|
* @return success
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
private boolean createAltPrivateKey() {
|
||||||
|
if (PREFERRED_SIGTYPE == SigType.DSA_SHA1)
|
||||||
|
return false;
|
||||||
|
File keyFile = getPrivateKeyFile();
|
||||||
|
if (keyFile == null)
|
||||||
|
return false;
|
||||||
|
if (!keyFile.exists())
|
||||||
|
return false;
|
||||||
|
File altFile = getAlternatePrivateKeyFile();
|
||||||
|
if (altFile == null)
|
||||||
|
return false;
|
||||||
|
if (altFile.equals(keyFile))
|
||||||
|
return false;
|
||||||
|
if (altFile.exists())
|
||||||
|
return true;
|
||||||
|
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
|
||||||
|
FileOutputStream out = null;
|
||||||
|
try {
|
||||||
|
Destination dest = pkf.getDestination();
|
||||||
|
if (dest == null)
|
||||||
|
return false;
|
||||||
|
if (dest.getSigType() != SigType.DSA_SHA1)
|
||||||
|
return false;
|
||||||
|
PublicKey pub = dest.getPublicKey();
|
||||||
|
PrivateKey priv = pkf.getPrivKey();
|
||||||
|
SimpleDataStructure[] signingKeys = KeyGenerator.getInstance().generateSigningKeys(PREFERRED_SIGTYPE);
|
||||||
|
SigningPublicKey signingPubKey = (SigningPublicKey) signingKeys[0];
|
||||||
|
SigningPrivateKey signingPrivKey = (SigningPrivateKey) signingKeys[1];
|
||||||
|
KeyCertificate cert = new KeyCertificate(signingPubKey);
|
||||||
|
Destination d = new Destination();
|
||||||
|
d.setPublicKey(pub);
|
||||||
|
d.setSigningPublicKey(signingPubKey);
|
||||||
|
d.setCertificate(cert);
|
||||||
|
int len = signingPubKey.length();
|
||||||
|
if (len < 128) {
|
||||||
|
byte[] pad = new byte[128 - len];
|
||||||
|
RandomSource.getInstance().nextBytes(pad);
|
||||||
|
d.setPadding(pad);
|
||||||
|
} else if (len > 128) {
|
||||||
|
// copy of excess data handled in KeyCertificate constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
out = new SecureFileOutputStream(altFile);
|
||||||
|
d.writeBytes(out);
|
||||||
|
priv.writeBytes(out);
|
||||||
|
signingPrivKey.writeBytes(out);
|
||||||
|
try { out.close(); } catch (IOException ioe) {}
|
||||||
|
|
||||||
|
String destStr = d.toBase64();
|
||||||
|
log("Alternate private key created and saved in " + altFile.getAbsolutePath());
|
||||||
|
log("You should backup this file in a secure place.");
|
||||||
|
log("New destination: " + destStr);
|
||||||
|
String b32 = d.toBase32();
|
||||||
|
log("Base32: " + b32);
|
||||||
|
File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR);
|
||||||
|
if (backupDir.isDirectory() || backupDir.mkdir()) {
|
||||||
|
String name = b32 + '-' + I2PAppContext.getGlobalContext().clock().now() + ".dat";
|
||||||
|
File backup = new File(backupDir, name);
|
||||||
|
if (FileUtil.copy(altFile, backup, false, true)) {
|
||||||
|
SecureFileOutputStream.setPerms(backup);
|
||||||
|
log("Alternate private key backup saved to " + backup.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
log("Error creating keys " + e);
|
||||||
|
return false;
|
||||||
|
} catch (I2PSessionException e) {
|
||||||
|
log("Error creating keys " + e);
|
||||||
|
return false;
|
||||||
|
} catch (I2PException e) {
|
||||||
|
log("Error creating keys " + e);
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log("Error creating keys " + e);
|
||||||
|
return false;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log("Error creating keys " + e);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startTunnelBackground() {
|
public void startTunnelBackground() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD)
|
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD)
|
||||||
@ -267,13 +380,17 @@ public class TunnelController implements Logging {
|
|||||||
}
|
}
|
||||||
// Config options may have changed since instantiation, so do this again.
|
// Config options may have changed since instantiation, so do this again.
|
||||||
// Or should we take it out of the constructor completely?
|
// Or should we take it out of the constructor completely?
|
||||||
if (type.endsWith("server") || getPersistentClientKey()) {
|
if (!isClient() || getPersistentClientKey()) {
|
||||||
boolean ok = createPrivateKey();
|
boolean ok = createPrivateKey();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
changeState(TunnelState.STOPPED);
|
changeState(TunnelState.STOPPED);
|
||||||
log("Failed to start tunnel " + getName() + " as the private key file could not be created");
|
log("Failed to start tunnel " + getName() + " as the private key file could not be created");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!isClient() && !getType().equals(TYPE_STREAMR_SERVER)) {
|
||||||
|
// check rv?
|
||||||
|
createAltPrivateKey();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setI2CPOptions();
|
setI2CPOptions();
|
||||||
setSessionOptions();
|
setSessionOptions();
|
||||||
@ -641,6 +758,7 @@ public class TunnelController implements Logging {
|
|||||||
props.setProperty(key, val);
|
props.setProperty(key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Properties oldConfig = _config;
|
||||||
_config = props;
|
_config = props;
|
||||||
|
|
||||||
// Set up some per-type defaults
|
// Set up some per-type defaults
|
||||||
@ -685,6 +803,15 @@ public class TunnelController implements Logging {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldConfig != null) {
|
||||||
|
if (configChanged(_config, oldConfig, PROP_FILE) ||
|
||||||
|
configChanged(_config, oldConfig, OPT_ALT_PKF) ||
|
||||||
|
configChanged(_config, oldConfig, OPT_SIG_TYPE)) {
|
||||||
|
log("Tunnel must be stopped and restarted for private key file changes to take effect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Running, so check sessions
|
// Running, so check sessions
|
||||||
Collection<I2PSession> sessions = getAllSessions();
|
Collection<I2PSession> sessions = getAllSessions();
|
||||||
if (sessions.isEmpty()) {
|
if (sessions.isEmpty()) {
|
||||||
@ -704,6 +831,17 @@ public class TunnelController implements Logging {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is property p different in p1 and p2?
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
private static boolean configChanged(Properties p1, Properties p2, String p) {
|
||||||
|
String s1 = p1.getProperty(p);
|
||||||
|
String s2 = p2.getProperty(p);
|
||||||
|
return (s1 != null && !s1.equals(s2)) ||
|
||||||
|
(s1 == null && s2 != null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a copy
|
* @return a copy
|
||||||
*/
|
*/
|
||||||
@ -797,7 +935,25 @@ public class TunnelController implements Logging {
|
|||||||
* @since 0.9.17
|
* @since 0.9.17
|
||||||
*/
|
*/
|
||||||
public File getPrivateKeyFile() {
|
public File getPrivateKeyFile() {
|
||||||
String f = getPrivKeyFile();
|
return filenameToFile(getPrivKeyFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does not necessarily exist.
|
||||||
|
* @return absolute path or null if unset
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public File getAlternatePrivateKeyFile() {
|
||||||
|
return filenameToFile(_config.getProperty(OPT_ALT_PKF));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does not necessarily exist.
|
||||||
|
* @param f relative or absolute path, may be null
|
||||||
|
* @return absolute path or null
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
static File filenameToFile(String f) {
|
||||||
if (f == null)
|
if (f == null)
|
||||||
return null;
|
return null;
|
||||||
f = f.trim();
|
f = f.trim();
|
||||||
|
@ -119,7 +119,7 @@ public class I2PTunnelDCCServer extends I2PTunnelServer {
|
|||||||
_active.put(Integer.valueOf(myPort), local);
|
_active.put(Integer.valueOf(myPort), local);
|
||||||
} catch (SocketException ex) {
|
} catch (SocketException ex) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.reset();
|
||||||
} catch (IOException ioe) {}
|
} catch (IOException ioe) {}
|
||||||
_log.error("Error relaying incoming DCC connection to IRC client at " + local.ia + ':' + local.port, ex);
|
_log.error("Error relaying incoming DCC connection to IRC client at " + local.ia + ':' + local.port, ex);
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,14 @@ class SocketWrapper implements I2PSocket {
|
|||||||
socket.close();
|
socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just calls close()
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void reset() throws IOException {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return socket.isClosed();
|
return socket.isClosed();
|
||||||
}
|
}
|
||||||
|
@ -264,14 +264,23 @@ public class GeneralHelper {
|
|||||||
return (tun != null && tun.getSpoofedHost() != null) ? tun.getSpoofedHost() : "";
|
return (tun != null && tun.getSpoofedHost() != null) ? tun.getSpoofedHost() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return path, non-null, non-empty
|
||||||
|
*/
|
||||||
public String getPrivateKeyFile(int tunnel) {
|
public String getPrivateKeyFile(int tunnel) {
|
||||||
return getPrivateKeyFile(_group, tunnel);
|
return getPrivateKeyFile(_group, tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return path, non-null, non-empty
|
||||||
|
*/
|
||||||
public String getPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) {
|
public String getPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) {
|
||||||
TunnelController tun = getController(tcg, tunnel);
|
TunnelController tun = getController(tcg, tunnel);
|
||||||
if (tun != null && tun.getPrivKeyFile() != null)
|
if (tun != null) {
|
||||||
return tun.getPrivKeyFile();
|
String rv = tun.getPrivKeyFile();
|
||||||
|
if (rv != null)
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
if (tunnel < 0)
|
if (tunnel < 0)
|
||||||
tunnel = tcg == null ? 999 : tcg.getControllers().size();
|
tunnel = tcg == null ? 999 : tcg.getControllers().size();
|
||||||
String rv = "i2ptunnel" + tunnel + "-privKeys.dat";
|
String rv = "i2ptunnel" + tunnel + "-privKeys.dat";
|
||||||
@ -284,6 +293,28 @@ public class GeneralHelper {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return path or ""
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getAltPrivateKeyFile(int tunnel) {
|
||||||
|
return getAltPrivateKeyFile(_group, tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return path or ""
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getAltPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) {
|
||||||
|
TunnelController tun = getController(tcg, tunnel);
|
||||||
|
if (tun != null) {
|
||||||
|
File f = tun.getAlternatePrivateKeyFile();
|
||||||
|
if (f != null)
|
||||||
|
return f.getAbsolutePath();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
public String getClientInterface(int tunnel) {
|
public String getClientInterface(int tunnel) {
|
||||||
TunnelController tun = getController(tunnel);
|
TunnelController tun = getController(tunnel);
|
||||||
if (tun != null) {
|
if (tun != null) {
|
||||||
@ -357,6 +388,29 @@ public class GeneralHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works even if tunnel is not running.
|
||||||
|
* @return Destination or null
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public Destination getAltDestination(int tunnel) {
|
||||||
|
TunnelController tun = getController(tunnel);
|
||||||
|
if (tun != null) {
|
||||||
|
// do this the hard way
|
||||||
|
File keyFile = tun.getAlternatePrivateKeyFile();
|
||||||
|
if (keyFile != null) {
|
||||||
|
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
|
||||||
|
try {
|
||||||
|
Destination rv = pkf.getDestination();
|
||||||
|
if (rv != null)
|
||||||
|
return rv;
|
||||||
|
} catch (I2PException e) {
|
||||||
|
} catch (IOException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean shouldStartAutomatically(int tunnel) {
|
public boolean shouldStartAutomatically(int tunnel) {
|
||||||
TunnelController tun = getController(tunnel);
|
TunnelController tun = getController(tunnel);
|
||||||
return tun != null ? tun.getStartOnLoad() : false;
|
return tun != null ? tun.getStartOnLoad() : false;
|
||||||
|
@ -161,6 +161,16 @@ public class TunnelConfig {
|
|||||||
public String getPrivKeyFile() {
|
public String getPrivKeyFile() {
|
||||||
return _privKeyFile;
|
return _privKeyFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What filename is this server tunnel's alternate private keys stored in
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void setAltPrivKeyFile(String file) {
|
||||||
|
if (file != null)
|
||||||
|
_otherOptions.put(I2PTunnelServer.PROP_ALT_PKF, file.trim());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If called with any value, we want this tunnel to start whenever it is
|
* If called with any value, we want this tunnel to start whenever it is
|
||||||
* loaded (aka right now and whenever the router is started up)
|
* loaded (aka right now and whenever the router is started up)
|
||||||
@ -725,7 +735,8 @@ public class TunnelConfig {
|
|||||||
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
||||||
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
||||||
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE,
|
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE,
|
||||||
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
|
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey",
|
||||||
|
I2PTunnelServer.PROP_ALT_PKF
|
||||||
};
|
};
|
||||||
private static final String _httpServerOpts[] = {
|
private static final String _httpServerOpts[] = {
|
||||||
I2PTunnelHTTPServer.OPT_POST_WINDOW,
|
I2PTunnelHTTPServer.OPT_POST_WINDOW,
|
||||||
|
@ -71,6 +71,14 @@ public class EditBean extends IndexBean {
|
|||||||
return _helper.getPrivateKeyFile(tunnel);
|
return _helper.getPrivateKeyFile(tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return path or ""
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getAltPrivateKeyFile(int tunnel) {
|
||||||
|
return _helper.getAltPrivateKeyFile(tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
public String getNameSignature(int tunnel) {
|
public String getNameSignature(int tunnel) {
|
||||||
String spoof = getSpoofedHost(tunnel);
|
String spoof = getSpoofedHost(tunnel);
|
||||||
|
@ -489,6 +489,39 @@ public class IndexBean {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works even if tunnel is not running.
|
||||||
|
* @return Destination or null
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
protected Destination getAltDestination(int tunnel) {
|
||||||
|
return _helper.getAltDestination(tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works even if tunnel is not running.
|
||||||
|
* @return Base64 or ""
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getAltDestinationBase64(int tunnel) {
|
||||||
|
Destination d = getAltDestination(tunnel);
|
||||||
|
if (d != null)
|
||||||
|
return d.toBase64();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works even if tunnel is not running.
|
||||||
|
* @return "{52 chars}.b32.i2p" or ""
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public String getAltDestHashBase32(int tunnel) {
|
||||||
|
Destination d = getAltDestination(tunnel);
|
||||||
|
if (d != null)
|
||||||
|
return d.toBase32();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For index.jsp
|
* For index.jsp
|
||||||
* @return true if the plugin is enabled, installed, and running
|
* @return true if the plugin is enabled, installed, and running
|
||||||
@ -613,10 +646,20 @@ public class IndexBean {
|
|||||||
public void setSpoofedHost(String host) {
|
public void setSpoofedHost(String host) {
|
||||||
_config.setSpoofedHost(host);
|
_config.setSpoofedHost(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** What filename is this server tunnel's private keys stored in */
|
/** What filename is this server tunnel's private keys stored in */
|
||||||
public void setPrivKeyFile(String file) {
|
public void setPrivKeyFile(String file) {
|
||||||
_config.setPrivKeyFile(file);
|
_config.setPrivKeyFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What filename is this server tunnel's alternate private keys stored in
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void setAltPrivKeyFile(String file) {
|
||||||
|
_config.setAltPrivKeyFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If called with any value (and the form submitted with action=Remove),
|
* If called with any value (and the form submitted with action=Remove),
|
||||||
* we really do want to stop and remove the tunnel.
|
* we really do want to stop and remove the tunnel.
|
||||||
|
@ -735,8 +735,9 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
</div>
|
</div>
|
||||||
<% **********************/ %>
|
<% **********************/ %>
|
||||||
|
|
||||||
<% if (true /* editBean.isAdvanced() */ ) {
|
<%
|
||||||
int currentSigType = editBean.getSigType(curTunnel, tunnelType);
|
int currentSigType = editBean.getSigType(curTunnel, tunnelType);
|
||||||
|
if (true /* editBean.isAdvanced() */ ) {
|
||||||
%>
|
%>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">
|
<th colspan="2">
|
||||||
@ -779,6 +780,50 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
|
|
||||||
<% } // isAdvanced %>
|
<% } // isAdvanced %>
|
||||||
|
|
||||||
|
<%
|
||||||
|
/* alternate dest, only if current dest is set and is DSA_SHA1 */
|
||||||
|
|
||||||
|
if (currentSigType == 0 && !"".equals(b64) && !"streamrserver".equals(tunnelType)) {
|
||||||
|
%><div id="privKeyField" class="rowItem">
|
||||||
|
<label for="privKeyFile"><%=intl._t("Alternate private key file")%> (Ed25519-SHA-512):</label>
|
||||||
|
<input type="text" size="30" id="privKeyFile" name="altPrivKeyFile" title="Path to Private Key File" value="<%=editBean.getAltPrivateKeyFile(curTunnel)%>" class="freetext" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%
|
||||||
|
String ab64 = editBean.getAltDestinationBase64(curTunnel);
|
||||||
|
if (!"".equals(ab64)) {
|
||||||
|
%><div id="destinationField" class="rowItem">
|
||||||
|
<label for="localDestination"><%=intl._t("Alternate local destination")%>:</label>
|
||||||
|
<textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Read Only: Alternate Local Destination" wrap="off" spellcheck="false"><%=ab64%></textarea>
|
||||||
|
</div>
|
||||||
|
<div id="destinationField" class="rowItem">
|
||||||
|
<label> </label>
|
||||||
|
<span class="comment"><%=editBean.getAltDestHashBase32(curTunnel)%></span>
|
||||||
|
</div>
|
||||||
|
<div id="destinationField" class="rowItem">
|
||||||
|
<%
|
||||||
|
ab64 = ab64.replace("=", "%3d");
|
||||||
|
String name = editBean.getSpoofedHost(curTunnel);
|
||||||
|
if (name == null || name.equals(""))
|
||||||
|
name = editBean.getTunnelName(curTunnel);
|
||||||
|
// mysite.i2p is set in the installed i2ptunnel.config
|
||||||
|
if (name != null && !name.equals("") && !name.equals("mysite.i2p") && !name.contains(" ") && name.endsWith(".i2p")) {
|
||||||
|
%><label>
|
||||||
|
<a class="control" title="<%=intl._t("Generate QR Code")%>" href="/imagegen/qr?s=320&t=<%=name%>&c=http%3a%2f%2f<%=name%>%2f%3fi2paddresshelper%3d<%=ab64%>" target="_top"><%=intl._t("Generate QR Code")%></a>
|
||||||
|
</label>
|
||||||
|
<a class="control" href="/susidns/addressbook.jsp?book=private&hostname=<%=name%>&destination=<%=ab64%>#add"><%=intl._t("Add to local addressbook")%></a>
|
||||||
|
<%
|
||||||
|
} else {
|
||||||
|
%><label> </label>
|
||||||
|
<span class="comment"><%=intl._t("Set name with .i2p suffix to enable QR code generation")%></span>
|
||||||
|
<%
|
||||||
|
} // name
|
||||||
|
%></div>
|
||||||
|
<%
|
||||||
|
} // ab64
|
||||||
|
%><div class="subdivider"><hr /></div>
|
||||||
|
<% } // currentSigType %>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">
|
<th colspan="2">
|
||||||
<%=intl._t("Custom options")%>
|
<%=intl._t("Custom options")%>
|
||||||
|
@ -91,6 +91,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
<!--
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<b><%=intl._t("Local Destination")%></b>
|
<b><%=intl._t("Local Destination")%></b>
|
||||||
@ -101,6 +102,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
<textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Read Only: Local Destination (if known)" wrap="off" spellcheck="false"><%=editBean.getDestinationBase64(curTunnel)%></textarea>
|
<textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Read Only: Local Destination (if known)" wrap="off" spellcheck="false"><%=editBean.getDestinationBase64(curTunnel)%></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
-->
|
||||||
|
|
||||||
<%
|
<%
|
||||||
if (b64 == null || b64.length() < 516) {
|
if (b64 == null || b64.length() < 516) {
|
||||||
@ -305,12 +307,40 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
<%=intl._t("This will add an alternate destination for {0}", name)%>
|
<%=intl._t("This will add an alternate destination for {0}", name)%>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<%
|
||||||
|
} else {
|
||||||
|
// If set, use the configured alternate destination as the new alias destination,
|
||||||
|
// and the configured primary destination as the inner signer.
|
||||||
|
// This is backwards from all the other ones, so we have to make a second HostTxtEntry just for this.
|
||||||
|
SigningPrivateKey spk3 = null;
|
||||||
|
String altdest = null;
|
||||||
|
String altdestfile = editBean.getAltPrivateKeyFile(curTunnel);
|
||||||
|
if (altdestfile.length() > 0) {
|
||||||
|
try {
|
||||||
|
PrivateKeyFile pkf3 = new PrivateKeyFile(altdestfile);
|
||||||
|
altdest = pkf3.getDestination().toBase64();
|
||||||
|
if (!b64.equals(altdest)) {
|
||||||
|
// disallow dup
|
||||||
|
spk3 = pkf3.getSigningPrivKey();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
if (spk3 != null) {
|
||||||
|
OrderedProperties props2 = new OrderedProperties();
|
||||||
|
HostTxtEntry he2 = new HostTxtEntry(name, altdest, props2);
|
||||||
|
props2.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_ADDDEST);
|
||||||
|
props2.setProperty(HostTxtEntry.PROP_OLDDEST, b64);
|
||||||
|
he2.signInner(spk);
|
||||||
|
he2.sign(spk3);
|
||||||
|
%><tr><td><textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Copy and paste this to the registration site" wrap="off" spellcheck="false"><% he2.write(out); %></textarea></td></tr>
|
||||||
|
<tr><td class="infohelp"><%=intl._t("This will add an alternate destination for {0}", name)%></td></tr>
|
||||||
<%
|
<%
|
||||||
} else {
|
} else {
|
||||||
%><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new destination.")%>
|
%><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new destination.")%>
|
||||||
<%=intl._t("Enter old destination below.")%></td></tr>
|
<%=intl._t("Enter old destination below.")%></td></tr>
|
||||||
<%
|
<%
|
||||||
}
|
} // spk3
|
||||||
|
} // spk2
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%
|
<%
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
Apache Tomcat
|
|
||||||
Copyright 1999-2016 The Apache Software Foundation
|
|
||||||
|
|
||||||
This product includes software developed at
|
|
||||||
The Apache Software Foundation (http://www.apache.org/).
|
|
||||||
|
|
||||||
The Windows Installer is built with the Nullsoft
|
|
||||||
Scriptable Install System (NSIS), which is
|
|
||||||
open source software. The original software and
|
|
||||||
related information is available at
|
|
||||||
http://nsis.sourceforge.net.
|
|
||||||
|
|
||||||
Java compilation software for JSP pages is provided by the Eclipse
|
|
||||||
JDT Core Batch Compiler component, which is open source software.
|
|
||||||
The original software and related information is available at
|
|
||||||
http://www.eclipse.org/jdt/core/.
|
|
||||||
|
|
||||||
The original XML Schemas for Java EE Deployment Descriptors:
|
|
||||||
- javaee_5.xsd
|
|
||||||
- javaee_web_services_1_2.xsd
|
|
||||||
- javaee_web_services_client_1_2.xsd
|
|
||||||
may be obtained from http://java.sun.com/xml/ns/javaee/
|
|
@ -1,26 +0,0 @@
|
|||||||
This is Apache Tomcat 6.x, supporting Servlet 2.5 and JSP 2.1.
|
|
||||||
The Glassfish JSP 2.1 bundled in Jetty 6 is way too old.
|
|
||||||
|
|
||||||
Retrieved from the file
|
|
||||||
apache-tomcat-6.0.48-deployer.tar.gz
|
|
||||||
|
|
||||||
minus the following files and directores:
|
|
||||||
|
|
||||||
build.xml
|
|
||||||
deployer-howto.html
|
|
||||||
images/*
|
|
||||||
lib/catalina*
|
|
||||||
lib/jsp-api.jar (see below)
|
|
||||||
lib/servlet-api.jar (see below)
|
|
||||||
LICENSE (see ../../../licenses/LICENSE-Apache2.0.txt, it's also inside every jar)
|
|
||||||
RELEASE-NOTES
|
|
||||||
|
|
||||||
|
|
||||||
We could use the following API jars from Apache Tomcat 7.x, supporting Servlet 3.0 and JSP 2.2,
|
|
||||||
that are required for Jetty 8, but we just bundle the ones from Jetty 8 instead:
|
|
||||||
|
|
||||||
lib/jsp-api.jar
|
|
||||||
lib/servlet-api.jar
|
|
||||||
|
|
||||||
For more info:
|
|
||||||
http://tomcat.apache.org/whichversion.html
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,10 +0,0 @@
|
|||||||
This is Apache Tomcat 6.x, supporting Servlet 2.5 and JSP 2.1.
|
|
||||||
|
|
||||||
Retrieved from the file
|
|
||||||
apache-tomcat-6.0.48.tar.gz
|
|
||||||
|
|
||||||
containing only a small subset of lib/tomcat-coyote.jar.
|
|
||||||
|
|
||||||
See the buildTomcatUtilJar target in ../build.xml for the classes extracted and more information.
|
|
||||||
|
|
||||||
LICENSE: see ../../../licenses/LICENSE-Apache2.0.txt
|
|
Binary file not shown.
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<!-- This copies jars, with some modifications and renaming,
|
<!-- This copies jars, with some modifications and renaming,
|
||||||
from the jetty-distribution directory to the jettylib directory.
|
from the jetty-distribution directory to the jettylib directory.
|
||||||
This is disabled if the property with-libjetty8-java=true.
|
This is disabled if the property with-libjetty9-java=true.
|
||||||
|
|
||||||
This copies jars, with some modifications and renaming,
|
This copies jars, with some modifications and renaming,
|
||||||
from the apache-tomcat-deployer and apache-tomcat directories to the jettylib directory.
|
from the apache-tomcat-deployer and apache-tomcat directories to the jettylib directory.
|
||||||
@ -14,18 +14,17 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- Note: Please change all references in top-level build.xml if you update to a new Jetty! -->
|
<!-- Note: Please change all references in top-level build.xml if you update to a new Jetty! -->
|
||||||
<property name="jetty.ver" value="8.1.21.v20160908" />
|
<!-- unused until we go to 9.3 -->
|
||||||
|
<property name="jetty.branch" value="stable-9" />
|
||||||
|
<property name="jetty.ver" value="9.2.21.v20170120" />
|
||||||
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
|
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
|
||||||
<property name="jetty.sha1" value="9780e99e765fd7b9bb1aac8ba2bba374ac039764" />
|
<property name="jetty.sha1" value="3dcd4f66cc3f72800a2ee53fecf7b3f9d3f23eb2" />
|
||||||
<property name="jetty.filename" value="${jetty.base}.zip" />
|
<property name="jetty.filename" value="${jetty.base}.zip" />
|
||||||
<property name="jetty.url" value="http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/${jetty.ver}/${jetty.filename}" />
|
<!-- change jetty.ver to jetty.branch for 9.3 -->
|
||||||
|
<property name="jetty.url" value="http://central.maven.org/maven2/org/eclipse/jetty/jetty-distribution/${jetty.ver}/${jetty.filename}" />
|
||||||
<property name="verified.filename" value="verified.txt" />
|
<property name="verified.filename" value="verified.txt" />
|
||||||
<property name="javac.compilerargs" value="" />
|
<property name="javac.compilerargs" value="" />
|
||||||
<property name="javac.version" value="1.7" />
|
<property name="javac.version" value="1.7" />
|
||||||
<property name="tomcat.lib" value="apache-tomcat-deployer/lib" />
|
|
||||||
<property name="tomcat.ver" value="6.0.48" />
|
|
||||||
<property name="tomcat2.lib" value="apache-tomcat-${tomcat.ver}/lib" />
|
|
||||||
<property name="tomcat2.lib.small" value="apache-tomcat/lib" />
|
|
||||||
|
|
||||||
<target name="all" depends="build" />
|
<target name="all" depends="build" />
|
||||||
|
|
||||||
@ -41,7 +40,7 @@
|
|||||||
<target name="ensureJettylib1" >
|
<target name="ensureJettylib1" >
|
||||||
<condition property="jetty.zip.extracted" >
|
<condition property="jetty.zip.extracted" >
|
||||||
<or>
|
<or>
|
||||||
<istrue value="${with-libjetty8-java}" />
|
<istrue value="${with-libjetty9-java}" />
|
||||||
<available file="${jetty.base}" type="dir" />
|
<available file="${jetty.base}" type="dir" />
|
||||||
</or>
|
</or>
|
||||||
</condition>
|
</condition>
|
||||||
@ -53,7 +52,7 @@
|
|||||||
</condition>
|
</condition>
|
||||||
<condition property="verified.already" >
|
<condition property="verified.already" >
|
||||||
<or>
|
<or>
|
||||||
<istrue value="${with-libjetty8-java}" />
|
<istrue value="${with-libjetty9-java}" />
|
||||||
<istrue value="${jetty.zip.extracted}" />
|
<istrue value="${jetty.zip.extracted}" />
|
||||||
<and>
|
<and>
|
||||||
<available file="${jetty.filename}" />
|
<available file="${jetty.filename}" />
|
||||||
@ -120,10 +119,17 @@
|
|||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- Jetty and tomcat files -->
|
<!-- Jetty and tomcat files -->
|
||||||
<target name="copyJettylib" depends="mkJettylibdir, copyJettylib1, copyTomcatLib" />
|
<!--
|
||||||
|
We support the following configurations:
|
||||||
|
no system jars: Precise, Trusty
|
||||||
|
with-libtomcat8-java: Jessie (without backports), Wheezy
|
||||||
|
with-libtomcat8-java AND with-libjetty9-java: Xenial, Jessie (with backports), Stretch
|
||||||
|
with-libjetty9-java (only): not supported
|
||||||
|
-->
|
||||||
|
<target name="copyJettylib" depends="mkJettylibdir, copyJettylib1, copyTomcatLib1, copyJettylib2, copyTomcatLib" />
|
||||||
|
|
||||||
<!-- Jetty files only -->
|
<!-- Jetty files only -->
|
||||||
<target name="copyJettylib1" depends="extractJettylib" unless="${with-libjetty8-java}" >
|
<target name="copyJettylib1" depends="extractJettylib" unless="${with-libjetty9-java}" >
|
||||||
<!-- We copy everything to names without the version numbers so we
|
<!-- We copy everything to names without the version numbers so we
|
||||||
can update them later. Where there was something similar in Jetty 5/6,
|
can update them later. Where there was something similar in Jetty 5/6,
|
||||||
we use the same names so they will overwrite the Jetty 5/6 jar on upgrade.
|
we use the same names so they will overwrite the Jetty 5/6 jar on upgrade.
|
||||||
@ -166,43 +172,29 @@
|
|||||||
<attribute name="Note" value="Intentionally empty" />
|
<attribute name="Note" value="Intentionally empty" />
|
||||||
</manifest>
|
</manifest>
|
||||||
</jar>
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- If with-libtomcat8-java but not with-libjetty9-java, we don't do this -->
|
||||||
|
<target name="copyJettylib2" depends="extractJettylib" unless="${with-libtomcat8-java}" >
|
||||||
<jar destfile="jettylib/javax.servlet.jar" duplicate="preserve" filesetmanifest="mergewithoutmain" >
|
<jar destfile="jettylib/javax.servlet.jar" duplicate="preserve" filesetmanifest="mergewithoutmain" >
|
||||||
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties" src="${jetty.base}/lib/servlet-api-3.0.jar" />
|
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties" src="${jetty.base}/lib/servlet-api-3.1.jar" />
|
||||||
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties" src="${jetty.base}/lib/jsp/javax.servlet.jsp-2.2.0.v201112011158.jar" />
|
<!--
|
||||||
|
Jetty version - see below for why we don't use this one
|
||||||
|
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties" src="${jetty.base}/lib/jsp/javax.servlet.jsp-api-2.3.1.jar" />
|
||||||
|
-->
|
||||||
|
<!-- Apache version -->
|
||||||
|
<!-- Also includes org.apache.*, this is copied into jasper-runtime.jar below -->
|
||||||
|
<zipfileset includes="javax/**/*" src="${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.33.jar"/>
|
||||||
|
<!-- In Debian packages they are found in /usr/share/java/tomcat8-servlet-api.jar in the libtomcat8-java package -->
|
||||||
|
<!-- javax/servlet/jsp/resources are dups of those in apache-jsp jar -->
|
||||||
|
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties javax/servlet/jsp/resources/*" src="${jetty.base}/lib/jetty-schemas-3.1.jar" />
|
||||||
</jar>
|
</jar>
|
||||||
<!--
|
<!--
|
||||||
<delete file="jetty.tar" />
|
<delete file="jetty.tar" />
|
||||||
<delete dir="${jetty.base}" />
|
<delete dir="${jetty.base}" />
|
||||||
-->
|
-->
|
||||||
<!-- commons-logging.jar not in Jetty 6 but we have it in launch4j so copy it over,
|
|
||||||
needed for old plugins and things. We add tomcat-juli below.
|
|
||||||
-->
|
|
||||||
<!--
|
|
||||||
* Removed in 0.9.24, see ticket #1679
|
|
||||||
* Jetty now uses tomcat-juli (added below to commons-logging.jar), not commons-logging proper,
|
|
||||||
* and no known plugins use it either.
|
|
||||||
<jar destfile="jettylib/commons-logging.jar" filesetmanifest="mergewithoutmain" >
|
|
||||||
<zipfileset excludes="META-INF/LICENSE.txt META-INF/NOTICE.txt" src="../../installer/lib/launch4j/lib/commons-logging.jar" />
|
|
||||||
</jar>
|
|
||||||
-->
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- Tomcat util jar.
|
|
||||||
As of Tomcat 6.0.39, the deployer does not contain some classes that are required
|
|
||||||
to precompile jsps with tags (SusiDNS and i2p-bote).
|
|
||||||
These classes are in the main Tomcat package, in lib/tomcat-coyote.jar.
|
|
||||||
As the jar is 800 KB and we only need 12 KB of that, we extract the required classes
|
|
||||||
to a new jar, created and checked in using this target.
|
|
||||||
Apparently this is only required for precompilation of jsps, so this is put in
|
|
||||||
with the JspC compiler jasper-runtime.jar below.
|
|
||||||
-->
|
|
||||||
<target name="buildTomcatUtilJar" unless="${with-libservlet2.5-java}" >
|
|
||||||
<!-- take only what we need from the tomcat-coyote jar -->
|
|
||||||
<jar destfile="${tomcat2.lib.small}/tomcat-coyote-util.jar" >
|
|
||||||
<zipfileset src="${tomcat2.lib}/tomcat-coyote.jar"
|
|
||||||
includes="org/apache/tomcat/util/descriptor/* org/apache/tomcat/util/res/*" />
|
|
||||||
</jar>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Tomcat.
|
<!-- Tomcat.
|
||||||
The glassfish jars bundled in Jetty 6 are way too old.
|
The glassfish jars bundled in Jetty 6 are way too old.
|
||||||
@ -221,7 +213,7 @@
|
|||||||
-->
|
-->
|
||||||
<target name="copyTomcatLib" depends="mkJettylibdir, copyTomcatLib1, copyTomcatLib2, copyTomcatLib3" />
|
<target name="copyTomcatLib" depends="mkJettylibdir, copyTomcatLib1, copyTomcatLib2, copyTomcatLib3" />
|
||||||
|
|
||||||
<target name="copyTomcatLib1" unless="${with-libservlet2.5-java}" >
|
<target name="copyTomcatLib1" >
|
||||||
<condition property="with-libtomcat-java" >
|
<condition property="with-libtomcat-java" >
|
||||||
<or>
|
<or>
|
||||||
<istrue value="${with-libtomcat6-java}" />
|
<istrue value="${with-libtomcat6-java}" />
|
||||||
@ -233,34 +225,47 @@
|
|||||||
|
|
||||||
|
|
||||||
<target name="copyTomcatLib2" unless="${with-libtomcat-java}" >
|
<target name="copyTomcatLib2" unless="${with-libtomcat-java}" >
|
||||||
<!-- EL libs.
|
<!-- EL API and compiler libs.
|
||||||
Tomcat 6 has EL 2.1.
|
Tomcat 6 has EL 2.1.
|
||||||
Tomcat 7 / libservlet3.0 has EL 2.2.
|
Tomcat 7 / libservlet3.0 has EL 2.2.
|
||||||
|
Jetty 9 / Tomcat 8 / libservlet3.1 has EL 3.0.
|
||||||
According to http://stackoverflow.com/questions/7202686/differences-between-el-2-1-and-2-2
|
According to http://stackoverflow.com/questions/7202686/differences-between-el-2-1-and-2-2
|
||||||
2.2 is backwards-compatible with 2.1.
|
2.2 is backwards-compatible with 2.1.
|
||||||
-->
|
-->
|
||||||
<jar destfile="jettylib/commons-el.jar" duplicate="preserve" filesetmanifest="merge" >
|
<!-- the javax.el API, AND the com.sun.el parser -->
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper-el.jar" />
|
<!-- actually from jetty9, not tomcat8... this will fail unless we have the jetty files also -->
|
||||||
<zipfileset excludes="META-INF/**/*" src="${tomcat.lib}/el-api.jar" />
|
<jar destfile="jettylib/commons-el.jar" >
|
||||||
|
<!--
|
||||||
|
Jetty version
|
||||||
|
<zipfileset src="${jetty.base}/lib/jsp/javax.el-3.0.0.jar"/>
|
||||||
|
-->
|
||||||
|
<!-- Apache version -->
|
||||||
|
<zipfileset src="${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.33.jar"/>
|
||||||
</jar>
|
</jar>
|
||||||
|
|
||||||
<jar destfile="jettylib/jasper-runtime.jar" filesetmanifest="merge" >
|
<!-- actually from jetty9, not tomcat8... this will fail unless we have the jetty files also -->
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper.jar" />
|
<jar destfile="jettylib/jasper-runtime.jar" >
|
||||||
<zipfileset src="${tomcat2.lib.small}/tomcat-coyote-util.jar" />
|
<!--
|
||||||
</jar>
|
Jetty version
|
||||||
<!--
|
<zipfileset src="${jetty.base}/lib/jsp/javax.servlet.jsp-2.3.2.jar"/>
|
||||||
<jar destfile="jettylib/javax.servlet.jar" duplicate="preserve" filesetmanifest="mergewithoutmain" >
|
To be included in jasper-runtime.jar?
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/servlet-api.jar" />
|
Server complains "NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet" even with this included (but it still works).
|
||||||
<zipfileset excludes="META-INF/**/*" src="${tomcat.lib}/jsp-api.jar" />
|
The following file has the class, but /usr/share/java/jetty8-jsp.jar is empty
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-api.jar" />
|
We don't use this one, because we want to be consistent with Debian builds that
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-util.jar" />
|
must use Apache (aka libtomcat8).
|
||||||
</jar>
|
<zipfileset excludes="about.html about_files about_files/* META-INF/ECLIPSEF.* META-INF/eclipse.inf plugin.properties" src="${jetty.base}/lib/jsp/jetty-jsp-${jetty.ver}.jar" />
|
||||||
-->
|
|
||||||
<!-- Ant bug, don't set update and filesetmanifest or the update doesn't happen,
|
|
||||||
Their bug tracker claims fixed in 1.8.0 but broken for me in 1.8.1
|
|
||||||
-->
|
-->
|
||||||
|
<!-- Apache version -->
|
||||||
|
<!-- Also includes javax.servlet.jsp.*, this is copied into javax.servlet.jar above -->
|
||||||
|
<zipfileset includes="org/**/*" src="${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.33.jar"/>
|
||||||
|
<!-- required Jetty initializer (see RouterConsoleRunner) -->
|
||||||
|
<zipfileset src="${jetty.base}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-${jetty.ver}.jar"/>
|
||||||
|
</jar>
|
||||||
|
|
||||||
<jar destfile="jettylib/commons-logging.jar" update="true" >
|
<jar destfile="jettylib/commons-logging.jar" update="true" >
|
||||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-juli.jar" />
|
<manifest>
|
||||||
|
<attribute name="Note" value="Intentionally empty" />
|
||||||
|
</manifest>
|
||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
@ -263,4 +263,11 @@ public class I2PLogger implements Logger
|
|||||||
public String getName() {
|
public String getName() {
|
||||||
return "net.i2p.jetty.I2PLogger";
|
return "net.i2p.jetty.I2PLogger";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since Jetty 9
|
||||||
|
*/
|
||||||
|
public void debug(String msg, long arg) {
|
||||||
|
debug(msg, Long.valueOf(arg), null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import java.util.TimeZone;
|
|||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpHeaders;
|
|
||||||
import org.eclipse.jetty.http.PathMap;
|
import org.eclipse.jetty.http.PathMap;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.RequestLog;
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
@ -81,7 +80,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
private transient OutputStream _out;
|
private transient OutputStream _out;
|
||||||
private transient OutputStream _fileOut;
|
private transient OutputStream _fileOut;
|
||||||
private transient DateCache _logDateCache;
|
private transient DateCache _logDateCache;
|
||||||
private transient PathMap _ignorePathMap;
|
private transient PathMap<String> _ignorePathMap;
|
||||||
private transient Writer _writer;
|
private transient Writer _writer;
|
||||||
private transient ArrayList<Utf8StringBuilder> _buffers;
|
private transient ArrayList<Utf8StringBuilder> _buffers;
|
||||||
private transient char[] _copy;
|
private transient char[] _copy;
|
||||||
@ -286,7 +285,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
String addr = null;
|
String addr = null;
|
||||||
if (_preferProxiedForAddress)
|
if (_preferProxiedForAddress)
|
||||||
{
|
{
|
||||||
addr = request.getHeader(HttpHeaders.X_FORWARDED_FOR);
|
addr = request.getHeader("X-Forwarded-For");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
@ -310,7 +309,9 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
if (_logDateCache!=null)
|
if (_logDateCache!=null)
|
||||||
buf.append(_logDateCache.format(request.getTimeStamp()));
|
buf.append(_logDateCache.format(request.getTimeStamp()));
|
||||||
else
|
else
|
||||||
buf.append(request.getTimeStampBuffer().toString());
|
//buf.append(request.getTimeStampBuffer().toString());
|
||||||
|
// TODO SimpleDateFormat or something
|
||||||
|
buf.append(request.getTimeStamp());
|
||||||
|
|
||||||
buf.append("] \"");
|
buf.append("] \"");
|
||||||
buf.append(request.getMethod());
|
buf.append(request.getMethod());
|
||||||
@ -358,7 +359,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
{
|
{
|
||||||
synchronized(_writer)
|
synchronized(_writer)
|
||||||
{
|
{
|
||||||
buf.append(StringUtil.__LINE_SEPARATOR);
|
buf.append(System.getProperty("line.separator", "\n"));
|
||||||
int l=buf.length();
|
int l=buf.length();
|
||||||
if (l>_copy.length)
|
if (l>_copy.length)
|
||||||
l=_copy.length;
|
l=_copy.length;
|
||||||
@ -412,7 +413,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
_writer.write(Long.toString(System.currentTimeMillis() - request.getTimeStamp()));
|
_writer.write(Long.toString(System.currentTimeMillis() - request.getTimeStamp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
_writer.write(StringUtil.__LINE_SEPARATOR);
|
_writer.write(System.getProperty("line.separator", "\n"));
|
||||||
_writer.flush();
|
_writer.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,7 +430,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
Response response,
|
Response response,
|
||||||
Writer writer) throws IOException
|
Writer writer) throws IOException
|
||||||
{
|
{
|
||||||
String referer = request.getHeader(HttpHeaders.REFERER);
|
String referer = request.getHeader("Referer");
|
||||||
if (referer == null)
|
if (referer == null)
|
||||||
writer.write("\"-\" ");
|
writer.write("\"-\" ");
|
||||||
else
|
else
|
||||||
@ -439,7 +440,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
writer.write("\" ");
|
writer.write("\" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
String agent = request.getHeader(HttpHeaders.USER_AGENT);
|
String agent = request.getHeader("User-Agent");
|
||||||
if (agent == null)
|
if (agent == null)
|
||||||
writer.write("\"-\" ");
|
writer.write("\"-\" ");
|
||||||
else
|
else
|
||||||
@ -455,8 +456,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
{
|
{
|
||||||
if (_logDateFormat!=null)
|
if (_logDateFormat!=null)
|
||||||
{
|
{
|
||||||
_logDateCache = new DateCache(_logDateFormat, _logLocale);
|
_logDateCache = new DateCache(_logDateFormat, _logLocale, _logTimeZone);
|
||||||
_logDateCache.setTimeZoneID(_logTimeZone);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_filename != null)
|
if (_filename != null)
|
||||||
@ -472,7 +472,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
|||||||
|
|
||||||
if (_ignorePaths != null && _ignorePaths.length > 0)
|
if (_ignorePaths != null && _ignorePaths.length > 0)
|
||||||
{
|
{
|
||||||
_ignorePathMap = new PathMap();
|
_ignorePathMap = new PathMap<String>();
|
||||||
for (int i = 0; i < _ignorePaths.length; i++)
|
for (int i = 0; i < _ignorePaths.length; i++)
|
||||||
_ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]);
|
_ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import net.i2p.util.I2PAppThread;
|
|||||||
import net.i2p.util.PortMapper;
|
import net.i2p.util.PortMapper;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.NetworkConnector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
@ -130,10 +131,13 @@ public class JettyStart implements ClientApp {
|
|||||||
Server server = (Server) lc;
|
Server server = (Server) lc;
|
||||||
Connector[] connectors = server.getConnectors();
|
Connector[] connectors = server.getConnectors();
|
||||||
if (connectors.length > 0) {
|
if (connectors.length > 0) {
|
||||||
int port = connectors[0].getPort();
|
Connector conn = connectors[0];
|
||||||
|
if (conn instanceof NetworkConnector) {
|
||||||
|
NetworkConnector nconn = (NetworkConnector) conn;
|
||||||
|
int port = nconn.getPort();
|
||||||
if (port > 0) {
|
if (port > 0) {
|
||||||
_port = port;
|
_port = port;
|
||||||
String host = connectors[0].getHost();
|
String host = nconn.getHost();
|
||||||
if (host.equals("0.0.0.0") || host.equals("::"))
|
if (host.equals("0.0.0.0") || host.equals("::"))
|
||||||
host = "127.0.0.1";
|
host = "127.0.0.1";
|
||||||
_context.portMapper().register(PortMapper.SVC_EEPSITE, host, port);
|
_context.portMapper().register(PortMapper.SVC_EEPSITE, host, port);
|
||||||
@ -141,6 +145,7 @@ public class JettyStart implements ClientApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
changeState(START_FAILED, e);
|
changeState(START_FAILED, e);
|
||||||
return;
|
return;
|
||||||
|
@ -49,6 +49,7 @@ import org.mortbay.util.LineInput;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* Modded to compile with Jetty 6 for I2P
|
* Modded to compile with Jetty 6 for I2P
|
||||||
|
* Modded to make fields private and final
|
||||||
*
|
*
|
||||||
* @version $Id: MultiPartRequest.java,v 1.16 2005/12/02 20:13:52 gregwilkins Exp $
|
* @version $Id: MultiPartRequest.java,v 1.16 2005/12/02 20:13:52 gregwilkins Exp $
|
||||||
* @author Greg Wilkins
|
* @author Greg Wilkins
|
||||||
@ -59,14 +60,14 @@ public class MultiPartRequest
|
|||||||
//private static Log log = LogFactory.getLog(MultiPartRequest.class);
|
//private static Log log = LogFactory.getLog(MultiPartRequest.class);
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
HttpServletRequest _request;
|
private final HttpServletRequest _request;
|
||||||
LineInput _in;
|
private final LineInput _in;
|
||||||
String _boundary;
|
private final String _boundary;
|
||||||
String _encoding;
|
private final String _encoding;
|
||||||
byte[] _byteBoundary;
|
private final byte[] _byteBoundary;
|
||||||
MultiMap<String> _partMap = new MultiMap<String>(10);
|
private final MultiMap<String> _partMap = new MultiMap<String>(10);
|
||||||
int _char=-2;
|
private int _char=-2;
|
||||||
boolean _lastPart=false;
|
private boolean _lastPart=false;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/jetty/jetty-distribution-9.2.21.v20170120/start.jar
Normal file
BIN
apps/jetty/jetty-distribution-9.2.21.v20170120/start.jar
Normal file
Binary file not shown.
@ -113,6 +113,20 @@ public interface I2PSocket extends Closeable {
|
|||||||
*/
|
*/
|
||||||
public int getLocalPort();
|
public int getLocalPort();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets and closes this socket. Sends a RESET indication to the far-end.
|
||||||
|
* This is the equivalent of setSoLinger(true, 0) followed by close() on a Java Socket.
|
||||||
|
*
|
||||||
|
* Nonblocking.
|
||||||
|
* Any thread currently blocked in an I/O operation upon this socket will throw an IOException.
|
||||||
|
* Once a socket has been reset, it is not available for further networking use
|
||||||
|
* (i.e. can't be reconnected or rebound). A new socket needs to be created.
|
||||||
|
* Resetting this socket will also close the socket's InputStream and OutputStream.
|
||||||
|
*
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void reset() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deprecated, unimplemented, does nothing. Original description:
|
* Deprecated, unimplemented, does nothing. Original description:
|
||||||
*
|
*
|
||||||
|
@ -38,6 +38,10 @@ public interface I2PSocketManager {
|
|||||||
public I2PSession getSession();
|
public I2PSession getSession();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* For a server, you must call connect() on the returned object.
|
||||||
|
* Connecting the primary session does NOT connect any subsessions.
|
||||||
|
* If the primary session is not connected, connecting a subsession will connect the primary session first.
|
||||||
|
*
|
||||||
* @return a new subsession, non-null
|
* @return a new subsession, non-null
|
||||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||||
* and different signing keys
|
* and different signing keys
|
||||||
|
@ -70,11 +70,15 @@
|
|||||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/jetty-webapp.jar" />
|
<pathelement location="../../jetty/jettylib/jetty-webapp.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
||||||
<pathelement location="../../systray/java/build/systray.jar" />
|
<pathelement location="../../systray/java/build/systray.jar" />
|
||||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||||
<pathelement location="../../../installer/lib/wrapper/all/wrapper.jar" />
|
<pathelement location="../../../installer/lib/wrapper/all/wrapper.jar" />
|
||||||
<pathelement location="../../jrobin/java/build/jrobin.jar" />
|
<pathelement location="../../jrobin/java/build/jrobin.jar" />
|
||||||
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||||
</classpath>
|
</classpath>
|
||||||
</javac>
|
</javac>
|
||||||
</target>
|
</target>
|
||||||
@ -362,17 +366,22 @@
|
|||||||
** -trimSpaces Trim spaces in template text between actions, directives
|
** -trimSpaces Trim spaces in template text between actions, directives
|
||||||
-->
|
-->
|
||||||
<java classname="org.apache.jasper.JspC" fork="true" failonerror="true">
|
<java classname="org.apache.jasper.JspC" fork="true" failonerror="true">
|
||||||
|
<!-- this prevents tomcat from complaining in debian builds -->
|
||||||
|
<jvmarg value="-Dtomcat.util.scan.StandardJarScanFilter.jarsToSkip=commons-collections.jar,junit.jar,junit4.jar" />
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<!-- jsp-api.jar only present for debian builds -->
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<!-- tomcat-api.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||||
<!-- jasper-el.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||||
|
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
||||||
<pathelement location="../../systray/java/build/obj" />
|
<pathelement location="../../systray/java/build/obj" />
|
||||||
@ -403,10 +412,13 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<!-- jsp-api.jar only present for debian builds -->
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<!-- tomcat-api.jar only present for debian builds -->
|
|
||||||
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||||
|
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||||
|
@ -457,6 +457,13 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
statusDone("<b>" + _t("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
|
statusDone("<b>" + _t("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
String blacklistVersion = PluginStarter.jetty9Blacklist.get(appName);
|
||||||
|
if (blacklistVersion != null &&
|
||||||
|
VersionComparator.comp(version, blacklistVersion) <= 0) {
|
||||||
|
to.delete();
|
||||||
|
statusDone("<b>" + _t("Plugin requires Jetty version {0} or lower", "8.9999") + "</b>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
||||||
if (maxVersion != null &&
|
if (maxVersion != null &&
|
||||||
VersionComparator.comp(maxVersion, oldVersion) < 0) {
|
VersionComparator.comp(maxVersion, oldVersion) < 0) {
|
||||||
@ -480,7 +487,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
}
|
}
|
||||||
// we don't need the original file anymore.
|
// we don't need the original file anymore.
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _t("Plugin will be installed on next restart.") + "</b>");
|
statusDone("<b>" + _t("Plugin will be installed on next restart.") + ' ' + appName + ' ' + version + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PluginStarter.isPluginRunning(appName, _context)) {
|
if (PluginStarter.isPluginRunning(appName, _context)) {
|
||||||
@ -498,7 +505,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
} else {
|
} else {
|
||||||
if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
|
if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _t("Plugin is for upgrades only, but the plugin is not installed") + "</b>");
|
statusDone("<b>" + _t("Plugin is for upgrades only, but the plugin is not installed") + ". " + appName + ' ' + version + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!destDir.mkdir()) {
|
if (!destDir.mkdir()) {
|
||||||
@ -518,7 +525,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
to.delete();
|
to.delete();
|
||||||
// install != update. Changing the user's settings like this is probabbly a bad idea.
|
// install != update. Changing the user's settings like this is probabbly a bad idea.
|
||||||
if (Boolean.valueOf( props.getProperty("dont-start-at-install")).booleanValue()) {
|
if (Boolean.valueOf( props.getProperty("dont-start-at-install")).booleanValue()) {
|
||||||
statusDone("<b>" + _t("Plugin {0} installed", appName) + "</b>");
|
statusDone("<b>" + _t("Plugin {0} installed", appName + ' ' + version) + "</b>");
|
||||||
if(!update) {
|
if(!update) {
|
||||||
Properties pluginProps = PluginStarter.pluginProperties();
|
Properties pluginProps = PluginStarter.pluginProperties();
|
||||||
pluginProps.setProperty(PluginStarter.PREFIX + appName + PluginStarter.ENABLED, "false");
|
pluginProps.setProperty(PluginStarter.PREFIX + appName + PluginStarter.ENABLED, "false");
|
||||||
@ -534,19 +541,19 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
String linkURL = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
|
String linkURL = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
|
||||||
String link;
|
String link;
|
||||||
if (linkName != null && linkURL != null)
|
if (linkName != null && linkURL != null)
|
||||||
link = "<a target=\"_blank\" href=\"" + linkURL + "\"/>" + linkName + "</a>";
|
link = "<a target=\"_blank\" href=\"" + linkURL + "\"/>" + linkName + ' ' + version + "</a>";
|
||||||
else
|
else
|
||||||
link = appName;
|
link = appName + ' ' + version;
|
||||||
statusDone("<b>" + _t("Plugin {0} installed and started", link) + "</b>");
|
statusDone("<b>" + _t("Plugin {0} installed and started", link) + "</b>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
statusDone("<b>" + _t("Plugin {0} installed but failed to start, check logs", appName) + "</b>");
|
statusDone("<b>" + _t("Plugin {0} installed but failed to start, check logs", appName + ' ' + version) + "</b>");
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
statusDone("<b>" + _t("Plugin {0} installed but failed to start", appName) + ": " + e + "</b>");
|
statusDone("<b>" + _t("Plugin {0} installed but failed to start", appName + ' ' + version) + ": " + e + "</b>");
|
||||||
_log.error("Error starting plugin " + appName, e);
|
_log.error("Error starting plugin " + appName + ' ' + version, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
statusDone("<b>" + _t("Plugin {0} installed", appName) + "</b>");
|
statusDone("<b>" + _t("Plugin {0} installed", appName + ' ' + version) + "</b>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public class CodedIconRendererServlet extends HttpServlet {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
|
||||||
byte[] data;
|
byte[] data;
|
||||||
String name = srq.getParameter("plugin");
|
String name = srq.getParameter("plugin");
|
||||||
data = NavHelper.getBinary(name);
|
data = NavHelper.getBinary(name);
|
||||||
|
@ -573,7 +573,18 @@ public class ConfigClientsHandler extends FormHandler {
|
|||||||
private void startPlugin(String app) {
|
private void startPlugin(String app) {
|
||||||
try {
|
try {
|
||||||
PluginStarter.startPlugin(_context, app);
|
PluginStarter.startPlugin(_context, app);
|
||||||
|
// linkify the app name for the message if available
|
||||||
|
Properties props = PluginStarter.pluginProperties(_context, app);
|
||||||
|
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(_context));
|
||||||
|
if (name == null)
|
||||||
|
name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
|
||||||
|
String url = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
|
||||||
|
if (name != null && url != null && name.length() > 0 && url.length() > 0) {
|
||||||
|
app = "<a href=\"" + url + "\">" + name + "</a>";
|
||||||
|
addFormNoticeNoEscape(_t("Started plugin {0}", app));
|
||||||
|
} else {
|
||||||
addFormNotice(_t("Started plugin {0}", app));
|
addFormNotice(_t("Started plugin {0}", app));
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
addFormError(_t("Error starting plugin {0}", app) + ": " + e);
|
addFormError(_t("Error starting plugin {0}", app) + ": " + e);
|
||||||
_log.error("Error starting plugin " + app, e);
|
_log.error("Error starting plugin " + app, e);
|
||||||
|
@ -67,6 +67,22 @@ public class PluginStarter implements Runnable {
|
|||||||
private static Map<String, ClassLoader> _clCache = new ConcurrentHashMap<String, ClassLoader>();
|
private static Map<String, ClassLoader> _clCache = new ConcurrentHashMap<String, ClassLoader>();
|
||||||
private static Map<String, Collection<String>> pluginWars = new ConcurrentHashMap<String, Collection<String>>();
|
private static Map<String, Collection<String>> pluginWars = new ConcurrentHashMap<String, Collection<String>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin name to plugin version of plugins that do not work
|
||||||
|
* with Jetty 9, but do not have a max-jetty-version=8.9999 set.
|
||||||
|
* Unmodifiable.
|
||||||
|
*
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public static final Map<String, String> jetty9Blacklist;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<String, String> map = new HashMap<String, String>(4);
|
||||||
|
map.put("i2pbote", "0.4.5");
|
||||||
|
map.put("BwSchedule", "0.0.36");
|
||||||
|
jetty9Blacklist = Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
public PluginStarter(RouterContext ctx) {
|
public PluginStarter(RouterContext ctx) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
}
|
}
|
||||||
@ -297,8 +313,8 @@ public class PluginStarter implements Runnable {
|
|||||||
|
|
||||||
Properties props = pluginProperties(ctx, appName);
|
Properties props = pluginProperties(ctx, appName);
|
||||||
|
|
||||||
|
// For the following, we use the exact same translated strings as in PluginUpdateRunner
|
||||||
|
// to avoid duplication
|
||||||
|
|
||||||
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
@ -306,6 +322,7 @@ public class PluginStarter implements Runnable {
|
|||||||
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
|
foo = gettext("This plugin requires I2P version {0} or higher", minVersion, ctx);
|
||||||
throw new Exception(foo);
|
throw new Exception(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,6 +332,7 @@ public class PluginStarter implements Runnable {
|
|||||||
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
|
foo = gettext("This plugin requires Java version {0} or higher", minVersion, ctx);
|
||||||
throw new Exception(foo);
|
throw new Exception(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,6 +343,18 @@ public class PluginStarter implements Runnable {
|
|||||||
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
|
foo = gettext("Plugin requires Jetty version {0} or higher", minVersion, ctx);
|
||||||
|
throw new Exception(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
String blacklistVersion = jetty9Blacklist.get(appName);
|
||||||
|
String curVersion = ConfigClientsHelper.stripHTML(props, "version");
|
||||||
|
if (blacklistVersion != null &&
|
||||||
|
VersionComparator.comp(curVersion, blacklistVersion) <= 0) {
|
||||||
|
String foo = "Plugin " + appName + " requires Jetty version 8.9999 or lower";
|
||||||
|
log.error(foo);
|
||||||
|
disablePlugin(appName);
|
||||||
|
foo = gettext("Plugin requires Jetty version {0} or lower", "8.9999", ctx);
|
||||||
throw new Exception(foo);
|
throw new Exception(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +364,7 @@ public class PluginStarter implements Runnable {
|
|||||||
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
|
foo = gettext("Plugin requires Jetty version {0} or lower", maxVersion, ctx);
|
||||||
throw new Exception(foo);
|
throw new Exception(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,6 +1033,14 @@ public class PluginStarter implements Runnable {
|
|||||||
method.invoke(urlClassLoader, new Object[]{u});
|
method.invoke(urlClassLoader, new Object[]{u});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translate a string
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
private static String gettext(String s, Object o, I2PAppContext ctx) {
|
||||||
|
return Messages.getString(s, o, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/** translate a string */
|
/** translate a string */
|
||||||
private static String ngettext(String s, String p, int n, I2PAppContext ctx) {
|
private static String ngettext(String s, String p, int n, I2PAppContext ctx) {
|
||||||
return Messages.getString(n, s, p, ctx);
|
return Messages.getString(n, s, p, ctx);
|
||||||
|
@ -17,9 +17,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
@ -46,19 +46,21 @@ import org.eclipse.jetty.security.ConstraintMapping;
|
|||||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||||
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
||||||
import org.eclipse.jetty.server.AbstractConnector;
|
import org.eclipse.jetty.server.AbstractConnector;
|
||||||
|
import org.eclipse.jetty.server.ConnectionFactory;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
import org.eclipse.jetty.server.NCSARequestLog;
|
import org.eclipse.jetty.server.NCSARequestLog;
|
||||||
|
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
|
||||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
|
||||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
|
||||||
import org.eclipse.jetty.servlet.ServletHandler;
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
@ -70,6 +72,7 @@ import org.eclipse.jetty.util.security.Credential.MD5;
|
|||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||||
|
|
||||||
import org.tanukisoftware.wrapper.WrapperManager;
|
import org.tanukisoftware.wrapper.WrapperManager;
|
||||||
@ -96,7 +99,7 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
private final ClientAppManager _mgr;
|
private final ClientAppManager _mgr;
|
||||||
private volatile ClientAppState _state = UNINITIALIZED;
|
private volatile ClientAppState _state = UNINITIALIZED;
|
||||||
private static Server _server;
|
private static Server _server;
|
||||||
private static Timer _jettyTimer;
|
private static ScheduledExecutorScheduler _jettyTimer;
|
||||||
private String _listenPort;
|
private String _listenPort;
|
||||||
private String _listenHost;
|
private String _listenHost;
|
||||||
private String _sslListenPort;
|
private String _sslListenPort;
|
||||||
@ -231,6 +234,7 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
changeState(STOPPING);
|
changeState(STOPPING);
|
||||||
if (PluginStarter.pluginsEnabled(_context))
|
if (PluginStarter.pluginsEnabled(_context))
|
||||||
(new I2PAppThread(new PluginStopper(_context), "PluginStopper")).start();
|
(new I2PAppThread(new PluginStopper(_context), "PluginStopper")).start();
|
||||||
|
stopAllWebApps();
|
||||||
try {
|
try {
|
||||||
_server.stop();
|
_server.stop();
|
||||||
} catch (Exception ie) {}
|
} catch (Exception ie) {}
|
||||||
@ -239,7 +243,9 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
portMapper.unregister(PortMapper.SVC_HTTPS_CONSOLE);
|
portMapper.unregister(PortMapper.SVC_HTTPS_CONSOLE);
|
||||||
synchronized(RouterConsoleRunner.class) {
|
synchronized(RouterConsoleRunner.class) {
|
||||||
if (_jettyTimer != null) {
|
if (_jettyTimer != null) {
|
||||||
_jettyTimer.cancel();
|
try {
|
||||||
|
_jettyTimer.stop();
|
||||||
|
} catch (Exception e) {}
|
||||||
_jettyTimer = null;
|
_jettyTimer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,6 +369,22 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
* DefaultHandler
|
* DefaultHandler
|
||||||
* RequestLogHandler (opt)
|
* RequestLogHandler (opt)
|
||||||
*</pre>
|
*</pre>
|
||||||
|
*
|
||||||
|
* Porting to Jetty 9:
|
||||||
|
*
|
||||||
|
* http://dev.eclipse.org/mhonarc/lists/jetty-dev/msg01952.html
|
||||||
|
* You are missing a few facts about Jetty 9.1 ...
|
||||||
|
* First, there are no longer any blocking connectors.
|
||||||
|
* Its all async / nio connectors now. (mainly because that's the direction that the servlet api 3.1 is taking)
|
||||||
|
*
|
||||||
|
* Next, there is only 1 connector. The ServerConnector.
|
||||||
|
* However, it takes 1 or more ConnectionFactory implementations to know how to handle the incoming connection.
|
||||||
|
* We have factories for HTTP (0.9 thru 1.1), SPDY, SSL-http, and SSL-npn so far.
|
||||||
|
* This list of factories will expand as the future of connectivity to web servers is ever growing (think HTTP/2)
|
||||||
|
*
|
||||||
|
* Use the embedded examples for help understanding this.
|
||||||
|
* http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java?id=jetty-9.1.0.RC0
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public void startConsole() {
|
public void startConsole() {
|
||||||
File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
|
File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
|
||||||
@ -375,8 +397,9 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
|
|
||||||
// so Jetty can find WebAppConfiguration
|
// so Jetty can find WebAppConfiguration
|
||||||
System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
|
System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
|
||||||
_server = new Server();
|
// FIXME
|
||||||
_server.setGracefulShutdown(1000);
|
// http://dev.eclipse.org/mhonarc/lists/jetty-users/msg03487.html
|
||||||
|
//_server.setGracefulShutdown(1000);
|
||||||
|
|
||||||
// In Jetty 6, QTP was not concurrent, so we switched to
|
// In Jetty 6, QTP was not concurrent, so we switched to
|
||||||
// ThreadPoolExecutor with a fixed-size queue, a set maxThreads,
|
// ThreadPoolExecutor with a fixed-size queue, a set maxThreads,
|
||||||
@ -408,14 +431,11 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
// class not found...
|
// class not found...
|
||||||
//System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
|
//System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
|
||||||
LinkedBlockingQueue<Runnable> lbq = new LinkedBlockingQueue<Runnable>(4*MAX_THREADS);
|
LinkedBlockingQueue<Runnable> lbq = new LinkedBlockingQueue<Runnable>(4*MAX_THREADS);
|
||||||
QueuedThreadPool qtp = new QueuedThreadPool(lbq);
|
// min and max threads will be reset below
|
||||||
// min and max threads will be set below
|
QueuedThreadPool qtp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, MAX_IDLE_TIME, lbq);
|
||||||
//qtp.setMinThreads(MIN_THREADS);
|
|
||||||
//qtp.setMaxThreads(MAX_THREADS);
|
|
||||||
qtp.setMaxIdleTimeMs(MAX_IDLE_TIME);
|
|
||||||
qtp.setName(THREAD_NAME);
|
qtp.setName(THREAD_NAME);
|
||||||
qtp.setDaemon(true);
|
qtp.setDaemon(true);
|
||||||
_server.setThreadPool(qtp);
|
_server = new Server(qtp);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
HandlerCollection hColl = new HandlerCollection();
|
HandlerCollection hColl = new HandlerCollection();
|
||||||
@ -502,27 +522,15 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
} finally {
|
} finally {
|
||||||
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
||||||
}
|
}
|
||||||
//if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
|
HttpConfiguration httpConfig = new HttpConfiguration();
|
||||||
// _server.addListener('[' + host + "]:" + _listenPort);
|
// number of acceptors, (default) number of selectors
|
||||||
//else
|
ServerConnector lsnr = new ServerConnector(_server, 1, 0,
|
||||||
// _server.addListener(host + ':' + _listenPort);
|
new HttpConnectionFactory(httpConfig));
|
||||||
AbstractConnector lsnr;
|
//lsnr.setUseDirectBuffers(false); // default true seems to be leaky
|
||||||
if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
|
|
||||||
SelectChannelConnector slsnr = new SelectChannelConnector();
|
|
||||||
slsnr.setUseDirectBuffers(false); // default true seems to be leaky
|
|
||||||
lsnr = slsnr;
|
|
||||||
} else {
|
|
||||||
// Jetty 6 and NIO on Java 5 don't get along that well
|
|
||||||
// Also: http://jira.codehaus.org/browse/JETTY-1238
|
|
||||||
// "Do not use GCJ with Jetty, it will not work."
|
|
||||||
// Actually it does if you don't use NIO
|
|
||||||
lsnr = new SocketConnector();
|
|
||||||
}
|
|
||||||
lsnr.setHost(host);
|
lsnr.setHost(host);
|
||||||
lsnr.setPort(lport);
|
lsnr.setPort(lport);
|
||||||
lsnr.setMaxIdleTime(90*1000); // default 10 sec
|
lsnr.setIdleTimeout(90*1000); // default 10 sec
|
||||||
lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
||||||
lsnr.setAcceptors(1); // default changed to 2 somewhere in Jetty 7?
|
|
||||||
//_server.addConnector(lsnr);
|
//_server.addConnector(lsnr);
|
||||||
connectors.add(lsnr);
|
connectors.add(lsnr);
|
||||||
boundAddresses++;
|
boundAddresses++;
|
||||||
@ -586,22 +594,19 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
} finally {
|
} finally {
|
||||||
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
||||||
}
|
}
|
||||||
// TODO if class not found use SslChannelConnector
|
HttpConfiguration httpConfig = new HttpConfiguration();
|
||||||
AbstractConnector ssll;
|
httpConfig.setSecureScheme("https");
|
||||||
if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
|
httpConfig.setSecurePort(sslPort);
|
||||||
SslSelectChannelConnector sssll = new SslSelectChannelConnector(sslFactory);
|
httpConfig.addCustomizer(new SecureRequestCustomizer());
|
||||||
sssll.setUseDirectBuffers(false); // default true seems to be leaky
|
// number of acceptors, (default) number of selectors
|
||||||
ssll = sssll;
|
ServerConnector ssll = new ServerConnector(_server, 1, 0,
|
||||||
} else {
|
new SslConnectionFactory(sslFactory, "http/1.1"),
|
||||||
// Jetty 6 and NIO on Java 5 don't get along that well
|
new HttpConnectionFactory(httpConfig));
|
||||||
SslSocketConnector sssll = new SslSocketConnector(sslFactory);
|
//sssll.setUseDirectBuffers(false); // default true seems to be leaky
|
||||||
ssll = sssll;
|
|
||||||
}
|
|
||||||
ssll.setHost(host);
|
ssll.setHost(host);
|
||||||
ssll.setPort(sslPort);
|
ssll.setPort(sslPort);
|
||||||
ssll.setMaxIdleTime(90*1000); // default 10 sec
|
ssll.setIdleTimeout(90*1000); // default 10 sec
|
||||||
ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
||||||
ssll.setAcceptors(1); // default changed to 2 somewhere in Jetty 7?
|
|
||||||
//_server.addConnector(ssll);
|
//_server.addConnector(ssll);
|
||||||
connectors.add(ssll);
|
connectors.add(ssll);
|
||||||
boundAddresses++;
|
boundAddresses++;
|
||||||
@ -638,17 +643,25 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
||||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||||
tmpdir.mkdir();
|
tmpdir.mkdir();
|
||||||
if (!SystemVersion.isWindows() && !SystemVersion.isMac() &&
|
|
||||||
_context.getBaseDir().getAbsolutePath().equals("/usr/share/i2p")) {
|
|
||||||
// We are using Tomcat 6, so the Debian patch doesn't apply.
|
|
||||||
// Remove when we switch to Tomcat 8
|
|
||||||
_context.logManager().getLog(Server.class).logAlways(net.i2p.util.Log.INFO, "Please ignore any InstanceManager warnings");
|
|
||||||
}
|
|
||||||
rootServletHandler = new ServletHandler();
|
rootServletHandler = new ServletHandler();
|
||||||
rootWebApp = new LocaleWebAppHandler(_context,
|
rootWebApp = new LocaleWebAppHandler(_context,
|
||||||
"/", _webAppsDir + ROUTERCONSOLE + ".war",
|
"/", _webAppsDir + ROUTERCONSOLE + ".war",
|
||||||
tmpdir, rootServletHandler);
|
tmpdir, rootServletHandler);
|
||||||
initialize(_context, (WebAppContext)(rootWebApp.getHandler()));
|
try {
|
||||||
|
// Not sure who is supposed to call this, but unless we do,
|
||||||
|
// all the jsps die NPE, because JspFactory.getDefaultContext() returns null.
|
||||||
|
// We probably have to do this because we don't bundle the Jetty annotations jar and scanner.
|
||||||
|
// This is only with Tomcat 8, not with the Jetty (Eclipse) jsp impl.
|
||||||
|
// Got a clue from this ancient post for Tomcat 6:
|
||||||
|
// https://bz.apache.org/bugzilla/show_bug.cgi?id=39804
|
||||||
|
// see also apps/jetty/build.xml
|
||||||
|
Class.forName("org.eclipse.jetty.apache.jsp.JettyJasperInitializer");
|
||||||
|
} catch (ClassNotFoundException cnfe) {
|
||||||
|
System.err.println("Warning: JettyJasperInitializer not found");
|
||||||
|
}
|
||||||
|
WebAppContext wac = (WebAppContext)(rootWebApp.getHandler());
|
||||||
|
initialize(_context, wac);
|
||||||
|
WebAppStarter.setWebAppConfiguration(wac);
|
||||||
chColl.addHandler(rootWebApp);
|
chColl.addHandler(rootWebApp);
|
||||||
|
|
||||||
} catch (Exception ioe) {
|
} catch (Exception ioe) {
|
||||||
@ -709,7 +722,13 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
for (int i = 0; i < fileNames.length; i++) {
|
for (int i = 0; i < fileNames.length; i++) {
|
||||||
String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
||||||
String enabled = props.getProperty(PREFIX + appName + ENABLED);
|
String enabled = props.getProperty(PREFIX + appName + ENABLED);
|
||||||
if (! "false".equals(enabled)) {
|
if (appName.equals("addressbook")) {
|
||||||
|
// addressbook.war is now empty, thread is started by SusiDNS
|
||||||
|
if (enabled != null) {
|
||||||
|
props.remove(PREFIX + "addressbook" + ENABLED);
|
||||||
|
rewrite = true;
|
||||||
|
}
|
||||||
|
} else if (! "false".equals(enabled)) {
|
||||||
try {
|
try {
|
||||||
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
||||||
WebAppStarter.startWebApp(_context, chColl, appName, path);
|
WebAppStarter.startWebApp(_context, chColl, appName, path);
|
||||||
@ -945,7 +964,12 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
// see HashSessionManager javadoc
|
// see HashSessionManager javadoc
|
||||||
synchronized(RouterConsoleRunner.class) {
|
synchronized(RouterConsoleRunner.class) {
|
||||||
if (_jettyTimer == null) {
|
if (_jettyTimer == null) {
|
||||||
_jettyTimer = new Timer("Console HashSessionScavenger", true);
|
_jettyTimer = new ScheduledExecutorScheduler("Console HashSessionScavenger", true);
|
||||||
|
try {
|
||||||
|
_jettyTimer.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Warning: ScheduledExecutorScheduler start failed: " + e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
context.getServletContext().setAttribute("org.eclipse.jetty.server.session.timer", _jettyTimer);
|
context.getServletContext().setAttribute("org.eclipse.jetty.server.session.timer", _jettyTimer);
|
||||||
}
|
}
|
||||||
@ -1018,6 +1042,32 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops all but the root webapp (routerconsole.war)
|
||||||
|
* In Jetty 9, stopping the server doesn't stop the non-root webapps,
|
||||||
|
* so we must do it here.
|
||||||
|
* There should be a better way to do this, possibly by
|
||||||
|
* making the webapps "managed".
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
private void stopAllWebApps() {
|
||||||
|
Properties props = webAppProperties(_context);
|
||||||
|
Set<String> keys = props.stringPropertyNames();
|
||||||
|
for (String name : keys) {
|
||||||
|
if (name.startsWith(PREFIX) && name.endsWith(ENABLED)) {
|
||||||
|
String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
|
||||||
|
if (ROUTERCONSOLE.equals(app))
|
||||||
|
continue;
|
||||||
|
if (WebAppStarter.isWebAppRunning(app)) {
|
||||||
|
try {
|
||||||
|
WebAppStarter.stopWebApp(app);
|
||||||
|
} catch (Throwable t) { t.printStackTrace(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class WarFilenameFilter implements FilenameFilter {
|
static class WarFilenameFilter implements FilenameFilter {
|
||||||
private static final WarFilenameFilter _filter = new WarFilenameFilter();
|
private static final WarFilenameFilter _filter = new WarFilenameFilter();
|
||||||
public static WarFilenameFilter instance() { return _filter; }
|
public static WarFilenameFilter instance() { return _filter; }
|
||||||
|
@ -15,6 +15,7 @@ import java.util.StringTokenizer;
|
|||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
|
||||||
|
import org.apache.tomcat.SimpleInstanceManager;
|
||||||
import org.eclipse.jetty.webapp.Configuration;
|
import org.eclipse.jetty.webapp.Configuration;
|
||||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
@ -97,7 +98,11 @@ public class WebAppConfiguration implements Configuration {
|
|||||||
// Ticket #957... don't know why...
|
// Ticket #957... don't know why...
|
||||||
// Only really required if started manually, but we don't know that from here
|
// Only really required if started manually, but we don't know that from here
|
||||||
cp = "jetty-util.jar";
|
cp = "jetty-util.jar";
|
||||||
} else ****/ if (pluginDir.exists()) {
|
****/
|
||||||
|
if (ctxPath.equals("/susidns")) {
|
||||||
|
// Old installs don't have this in their wrapper.config classpath
|
||||||
|
cp = "addressbook.jar";
|
||||||
|
} else if (pluginDir.exists()) {
|
||||||
File consoleDir = new File(pluginDir, "console");
|
File consoleDir = new File(pluginDir, "console");
|
||||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||||
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
|
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
|
||||||
@ -173,11 +178,13 @@ public class WebAppConfiguration implements Configuration {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Java 9 - assume everything in lib/ is in the classpath
|
// Java 9 - assume everything in lib/ is in the classpath
|
||||||
|
// except addressbook.jar
|
||||||
File libDir = new File(ctx.getBaseDir(), "lib");
|
File libDir = new File(ctx.getBaseDir(), "lib");
|
||||||
File[] files = libDir.listFiles();
|
File[] files = libDir.listFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
if (files[i].getName().endsWith(".jar"))
|
String name = files[i].getName();
|
||||||
|
if (name.endsWith(".jar") && !name.equals("addressbook.jar"))
|
||||||
rv.add(files[i].toURI());
|
rv.add(files[i].toURI());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,6 +198,10 @@ public class WebAppConfiguration implements Configuration {
|
|||||||
/** @since Jetty 7 */
|
/** @since Jetty 7 */
|
||||||
public void configure(WebAppContext context) throws Exception {
|
public void configure(WebAppContext context) throws Exception {
|
||||||
configureClassPath(context);
|
configureClassPath(context);
|
||||||
|
// do we just need one, in the ContextHandlerCollection, or one for each?
|
||||||
|
// http://stackoverflow.com/questions/17529936/issues-while-using-jetty-embedded-to-handle-jsp-jasperexception-unable-to-com
|
||||||
|
// https://github.com/jetty-project/embedded-jetty-jsp/blob/master/src/main/java/org/eclipse/jetty/demo/Main.java
|
||||||
|
context.getServletContext().setAttribute("org.apache.tomcat.InstanceManager", new SimpleInstanceManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since Jetty 7 */
|
/** @since Jetty 7 */
|
||||||
|
@ -109,17 +109,30 @@ public class WebAppStarter {
|
|||||||
|
|
||||||
// this does the passwords...
|
// this does the passwords...
|
||||||
RouterConsoleRunner.initialize(ctx, wac);
|
RouterConsoleRunner.initialize(ctx, wac);
|
||||||
|
setWebAppConfiguration(wac);
|
||||||
|
server.addHandler(wac);
|
||||||
|
server.mapContexts();
|
||||||
|
return wac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since Jetty 9
|
||||||
|
*/
|
||||||
|
static void setWebAppConfiguration(WebAppContext wac) {
|
||||||
// see WebAppConfiguration for info
|
// see WebAppConfiguration for info
|
||||||
String[] classNames = wac.getConfigurationClasses();
|
String[] classNames = wac.getConfigurationClasses();
|
||||||
|
// In Jetty 9, it doesn't set the defaults if we've already added one, but the
|
||||||
|
// defaults aren't set yet when we call the above. So we have to get the defaults.
|
||||||
|
// Without the default configuration, the web.xml isn't read, and the webapp
|
||||||
|
// won't respond to any requests, even though it appears to be running.
|
||||||
|
// See WebAppContext.loadConfigurations() in source
|
||||||
|
if (classNames.length == 0)
|
||||||
|
classNames = wac.getDefaultConfigurationClasses();
|
||||||
String[] newClassNames = new String[classNames.length + 1];
|
String[] newClassNames = new String[classNames.length + 1];
|
||||||
for (int j = 0; j < classNames.length; j++)
|
for (int j = 0; j < classNames.length; j++)
|
||||||
newClassNames[j] = classNames[j];
|
newClassNames[j] = classNames[j];
|
||||||
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
||||||
wac.setConfigurationClasses(newClassNames);
|
wac.setConfigurationClasses(newClassNames);
|
||||||
server.addHandler(wac);
|
|
||||||
server.mapContexts();
|
|
||||||
return wac;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,13 +61,13 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
|
|||||||
if (str != null) try { periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
if (str != null) try { periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
||||||
str = request.getParameter("end");
|
str = request.getParameter("end");
|
||||||
if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
||||||
boolean hideLegend = Boolean.parseBoolean((String) request.getParameter("hideLegend"));
|
boolean hideLegend = Boolean.parseBoolean(request.getParameter("hideLegend"));
|
||||||
boolean hideGrid = Boolean.parseBoolean((String) request.getParameter("hideGrid"));
|
boolean hideGrid = Boolean.parseBoolean(request.getParameter("hideGrid"));
|
||||||
boolean hideTitle = Boolean.parseBoolean((String) request.getParameter("hideTitle"));
|
boolean hideTitle = Boolean.parseBoolean(request.getParameter("hideTitle"));
|
||||||
boolean showEvents = Boolean.parseBoolean((String) request.getParameter("showEvents"));
|
boolean showEvents = Boolean.parseBoolean(request.getParameter("showEvents"));
|
||||||
boolean showCredit = false;
|
boolean showCredit = false;
|
||||||
if (request.getParameter("showCredit") != null)
|
if (request.getParameter("showCredit") != null)
|
||||||
showCredit = Boolean.parseBoolean((String) request.getParameter("showCredit"));
|
showCredit = Boolean.parseBoolean(request.getParameter("showCredit"));
|
||||||
if (fakeBw)
|
if (fakeBw)
|
||||||
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
|
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
|
||||||
else
|
else
|
||||||
|
@ -389,7 +389,7 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
|
|||||||
boolean ok = ssess.queueSocket(i2ps);
|
boolean ok = ssess.queueSocket(i2ps);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
_log.logAlways(Log.WARN, "Accept queue overflow for " + ssess);
|
_log.logAlways(Log.WARN, "Accept queue overflow for " + ssess);
|
||||||
try { i2ps.close(); } catch (IOException ioe) {}
|
try { i2ps.reset(); } catch (IOException ioe) {}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
@ -564,7 +564,7 @@ class SAMStreamSession implements SAMMessageSess {
|
|||||||
int id = createSocketHandler(i2ps, 0);
|
int id = createSocketHandler(i2ps, 0);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
_log.error("SAM STREAM session handler not created!");
|
_log.error("SAM STREAM session handler not created!");
|
||||||
i2ps.close();
|
i2ps.reset();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
|||||||
Log log = ctx.logManager().getLog(SAMv3StreamSession.class);
|
Log log = ctx.logManager().getLog(SAMv3StreamSession.class);
|
||||||
log.error("SSL error", gse);
|
log.error("SSL error", gse);
|
||||||
try {
|
try {
|
||||||
i2ps.close();
|
i2ps.reset();
|
||||||
} catch (IOException ee) {}
|
} catch (IOException ee) {}
|
||||||
throw new RuntimeException("SSL error", gse);
|
throw new RuntimeException("SSL error", gse);
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
|||||||
if (log.shouldLog(Log.WARN))
|
if (log.shouldLog(Log.WARN))
|
||||||
log.warn("Error forwarding", ioe);
|
log.warn("Error forwarding", ioe);
|
||||||
try {
|
try {
|
||||||
i2ps.close();
|
i2ps.reset();
|
||||||
} catch (IOException ee) {}
|
} catch (IOException ee) {}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
|||||||
clientServerSock.close();
|
clientServerSock.close();
|
||||||
} catch (IOException ee) {}
|
} catch (IOException ee) {}
|
||||||
try {
|
try {
|
||||||
i2ps.close();
|
i2ps.reset();
|
||||||
} catch (IOException ee) {}
|
} catch (IOException ee) {}
|
||||||
continue ;
|
continue ;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,32 @@ class I2PSocketFull implements I2PSocket {
|
|||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets and closes this socket. Sends a RESET indication to the far-end.
|
||||||
|
* This is the equivalent of setSoLinger(true, 0) followed by close() on a Java Socket.
|
||||||
|
*
|
||||||
|
* Nonblocking.
|
||||||
|
* Any thread currently blocked in an I/O operation upon this socket will throw an IOException.
|
||||||
|
* Once a socket has been reset, it is not available for further networking use
|
||||||
|
* (i.e. can't be reconnected or rebound). A new socket needs to be created.
|
||||||
|
* Resetting this socket will also close the socket's InputStream and OutputStream.
|
||||||
|
*
|
||||||
|
* @since 0.9.30
|
||||||
|
*/
|
||||||
|
public void reset() throws IOException {
|
||||||
|
Connection c = _connection;
|
||||||
|
if (c == null) return;
|
||||||
|
if (log.shouldLog(Log.INFO))
|
||||||
|
log.info("reset() called, connected? " + c.getIsConnected() + " : " + c, new Exception());
|
||||||
|
if (c.getIsConnected()) {
|
||||||
|
c.disconnect(false);
|
||||||
|
// this will cause any thread waiting in Connection.packetSendChoke()
|
||||||
|
// to throw an IOE
|
||||||
|
c.windowAdjusted();
|
||||||
|
}
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
Connection getConnection() { return _connection; }
|
Connection getConnection() { return _connection; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,6 +236,10 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* For a server, you must call connect() on the returned object.
|
||||||
|
* Connecting the primary session does NOT connect any subsessions.
|
||||||
|
* If the primary session is not connected, connecting a subsession will connect the primary session first.
|
||||||
|
*
|
||||||
* @return a new subsession, non-null
|
* @return a new subsession, non-null
|
||||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||||
* and different signing keys
|
* and different signing keys
|
||||||
|
@ -30,7 +30,9 @@ class MessageOutputStream extends OutputStream {
|
|||||||
private final AtomicBoolean _closed = new AtomicBoolean();
|
private final AtomicBoolean _closed = new AtomicBoolean();
|
||||||
private long _written;
|
private long _written;
|
||||||
private int _writeTimeout;
|
private int _writeTimeout;
|
||||||
private ByteCache _dataCache;
|
private final ByteCache _dataCache;
|
||||||
|
private final int _originalBufferSize;
|
||||||
|
private int _currentBufferSize;
|
||||||
private final Flusher _flusher;
|
private final Flusher _flusher;
|
||||||
private volatile long _lastBuffered;
|
private volatile long _lastBuffered;
|
||||||
/** if we enqueue data but don't flush it in this period, flush it passively */
|
/** if we enqueue data but don't flush it in this period, flush it passively */
|
||||||
@ -68,6 +70,8 @@ class MessageOutputStream extends OutputStream {
|
|||||||
DataReceiver receiver, int bufSize, int passiveFlushDelay) {
|
DataReceiver receiver, int bufSize, int passiveFlushDelay) {
|
||||||
super();
|
super();
|
||||||
_dataCache = ByteCache.getInstance(128, bufSize);
|
_dataCache = ByteCache.getInstance(128, bufSize);
|
||||||
|
_originalBufferSize = bufSize;
|
||||||
|
_currentBufferSize = bufSize;
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(MessageOutputStream.class);
|
_log = ctx.logManager().getLog(MessageOutputStream.class);
|
||||||
_buf = _dataCache.acquire().getData(); // new byte[bufSize];
|
_buf = _dataCache.acquire().getData(); // new byte[bufSize];
|
||||||
@ -75,7 +79,7 @@ class MessageOutputStream extends OutputStream {
|
|||||||
_dataLock = new Object();
|
_dataLock = new Object();
|
||||||
_writeTimeout = -1;
|
_writeTimeout = -1;
|
||||||
_passiveFlushDelay = passiveFlushDelay;
|
_passiveFlushDelay = passiveFlushDelay;
|
||||||
_nextBufferSize = -1;
|
_nextBufferSize = 0;
|
||||||
//_sendPeriodBeginTime = ctx.clock().now();
|
//_sendPeriodBeginTime = ctx.clock().now();
|
||||||
//_context.statManager().createRateStat("stream.sendBps", "How fast we pump data through the stream", "Stream", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
//_context.statManager().createRateStat("stream.sendBps", "How fast we pump data through the stream", "Stream", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||||
_flusher = new Flusher(timer);
|
_flusher = new Flusher(timer);
|
||||||
@ -92,7 +96,16 @@ class MessageOutputStream extends OutputStream {
|
|||||||
|
|
||||||
public int getWriteTimeout() { return _writeTimeout; }
|
public int getWriteTimeout() { return _writeTimeout; }
|
||||||
|
|
||||||
public void setBufferSize(int size) { _nextBufferSize = size; }
|
/**
|
||||||
|
* Caller should enforce a sane minimum.
|
||||||
|
*
|
||||||
|
* @param size must be greater than 0, and smaller than or equal to bufSize in constructor
|
||||||
|
*/
|
||||||
|
public void setBufferSize(int size) {
|
||||||
|
if (size <= 0 || size > _originalBufferSize)
|
||||||
|
return;
|
||||||
|
_nextBufferSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte b[]) throws IOException {
|
public void write(byte b[]) throws IOException {
|
||||||
@ -115,8 +128,11 @@ class MessageOutputStream extends OutputStream {
|
|||||||
// this is the only method that *adds* to the _buf, and all
|
// this is the only method that *adds* to the _buf, and all
|
||||||
// code that reads from it is synchronized
|
// code that reads from it is synchronized
|
||||||
synchronized (_dataLock) {
|
synchronized (_dataLock) {
|
||||||
|
// To simplify the code, and avoid losing data from shrinking the max size,
|
||||||
|
// we only update max size when current buffer is empty
|
||||||
|
final int maxBuffer = (_valid == 0) ? locked_updateBufferSize() : _currentBufferSize;
|
||||||
if (_buf == null) throw new IOException("closed (buffer went away)");
|
if (_buf == null) throw new IOException("closed (buffer went away)");
|
||||||
if (_valid + remaining < _buf.length) {
|
if (_valid + remaining < maxBuffer) {
|
||||||
// simply buffer the data, no flush
|
// simply buffer the data, no flush
|
||||||
System.arraycopy(b, cur, _buf, _valid, remaining);
|
System.arraycopy(b, cur, _buf, _valid, remaining);
|
||||||
_valid += remaining;
|
_valid += remaining;
|
||||||
@ -131,19 +147,17 @@ class MessageOutputStream extends OutputStream {
|
|||||||
// buffer whatever we can fit then flush,
|
// buffer whatever we can fit then flush,
|
||||||
// repeating until we've pushed all of the
|
// repeating until we've pushed all of the
|
||||||
// data through
|
// data through
|
||||||
int toWrite = _buf.length - _valid;
|
int toWrite = maxBuffer - _valid;
|
||||||
System.arraycopy(b, cur, _buf, _valid, toWrite);
|
System.arraycopy(b, cur, _buf, _valid, toWrite);
|
||||||
remaining -= toWrite;
|
remaining -= toWrite;
|
||||||
cur += toWrite;
|
cur += toWrite;
|
||||||
_valid = _buf.length;
|
_valid = maxBuffer;
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("write() direct valid = " + _valid);
|
_log.info("write() direct valid = " + _valid);
|
||||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||||
_written += _valid;
|
_written += _valid;
|
||||||
_valid = 0;
|
_valid = 0;
|
||||||
throwAnyError();
|
throwAnyError();
|
||||||
|
|
||||||
locked_updateBufferSize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ws != null) {
|
if (ws != null) {
|
||||||
@ -207,17 +221,21 @@ class MessageOutputStream extends OutputStream {
|
|||||||
/**
|
/**
|
||||||
* If the other side requested we shrink our buffer, do so.
|
* If the other side requested we shrink our buffer, do so.
|
||||||
*
|
*
|
||||||
|
* @return the current buffer size
|
||||||
*/
|
*/
|
||||||
private final void locked_updateBufferSize() {
|
private final int locked_updateBufferSize() {
|
||||||
int size = _nextBufferSize;
|
int size = _nextBufferSize;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
// update the buffer size to the requested amount
|
// update the buffer size to the requested amount
|
||||||
_dataCache.release(new ByteArray(_buf));
|
// No, never do this, to avoid ByteCache churn.
|
||||||
_dataCache = ByteCache.getInstance(128, size);
|
//_dataCache.release(new ByteArray(_buf));
|
||||||
ByteArray ba = _dataCache.acquire();
|
//_dataCache = ByteCache.getInstance(128, size);
|
||||||
_buf = ba.getData();
|
//ByteArray ba = _dataCache.acquire();
|
||||||
_nextBufferSize = -1;
|
//_buf = ba.getData();
|
||||||
|
_currentBufferSize = size;
|
||||||
|
_nextBufferSize = 0;
|
||||||
}
|
}
|
||||||
|
return _currentBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,7 +291,6 @@ class MessageOutputStream extends OutputStream {
|
|||||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||||
_written += _valid;
|
_written += _valid;
|
||||||
_valid = 0;
|
_valid = 0;
|
||||||
locked_updateBufferSize();
|
|
||||||
_dataLock.notifyAll();
|
_dataLock.notifyAll();
|
||||||
sent = true;
|
sent = true;
|
||||||
}
|
}
|
||||||
@ -336,7 +353,6 @@ class MessageOutputStream extends OutputStream {
|
|||||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||||
_written += _valid;
|
_written += _valid;
|
||||||
_valid = 0;
|
_valid = 0;
|
||||||
locked_updateBufferSize();
|
|
||||||
_dataLock.notifyAll();
|
_dataLock.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -409,7 +425,6 @@ class MessageOutputStream extends OutputStream {
|
|||||||
ba = new ByteArray(_buf);
|
ba = new ByteArray(_buf);
|
||||||
_buf = null;
|
_buf = null;
|
||||||
_valid = 0;
|
_valid = 0;
|
||||||
locked_updateBufferSize();
|
|
||||||
}
|
}
|
||||||
_dataLock.notifyAll();
|
_dataLock.notifyAll();
|
||||||
}
|
}
|
||||||
@ -494,7 +509,6 @@ class MessageOutputStream extends OutputStream {
|
|||||||
ws = target.writeData(_buf, 0, _valid);
|
ws = target.writeData(_buf, 0, _valid);
|
||||||
_written += _valid;
|
_written += _valid;
|
||||||
_valid = 0;
|
_valid = 0;
|
||||||
locked_updateBufferSize();
|
|
||||||
_dataLock.notifyAll();
|
_dataLock.notifyAll();
|
||||||
}
|
}
|
||||||
long afterBuild = System.currentTimeMillis();
|
long afterBuild = System.currentTimeMillis();
|
||||||
|
@ -13,6 +13,22 @@
|
|||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
<display-name>susidns</display-name>
|
<display-name>susidns</display-name>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>addressbook-runner</servlet-name>
|
||||||
|
<servlet-class>net.i2p.addressbook.servlet.Servlet</servlet-class>
|
||||||
|
<init-param>
|
||||||
|
<param-name>home</param-name>
|
||||||
|
<param-value>./addressbook</param-value>
|
||||||
|
</init-param>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>addressbook-runner</servlet-name>
|
||||||
|
<url-pattern>/addressbook-runner</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<!-- precompiled servlets -->
|
<!-- precompiled servlets -->
|
||||||
|
|
||||||
<!-- non-.jsp URLs -->
|
<!-- non-.jsp URLs -->
|
||||||
|
@ -16,20 +16,22 @@
|
|||||||
-->
|
-->
|
||||||
<pathelement location="${lib}/commons-el.jar" />
|
<pathelement location="${lib}/commons-el.jar" />
|
||||||
<pathelement location="${lib}/javax.servlet.jar"/>
|
<pathelement location="${lib}/javax.servlet.jar"/>
|
||||||
<!-- jsp-api.jar only present for debian builds -->
|
|
||||||
|
<!-- following jars only present for debian builds -->
|
||||||
<pathelement location="${lib}/jsp-api.jar" />
|
<pathelement location="${lib}/jsp-api.jar" />
|
||||||
<!-- tomcat-api.jar only present for debian builds -->
|
|
||||||
<pathelement location="${lib}/tomcat-api.jar" />
|
<pathelement location="${lib}/tomcat-api.jar" />
|
||||||
<!-- tomcat-util.jar only present for debian builds -->
|
|
||||||
<pathelement location="${lib}/tomcat-util.jar" />
|
<pathelement location="${lib}/tomcat-util.jar" />
|
||||||
|
<pathelement location="${lib}/tomcat-util-scan.jar" />
|
||||||
|
<pathelement location="${lib}/jasper-el.jar" />
|
||||||
|
|
||||||
<pathelement location="lib/jstl.jar" />
|
<pathelement location="lib/jstl.jar" />
|
||||||
<pathelement location="lib/standard.jar" />
|
<pathelement location="lib/standard.jar" />
|
||||||
<pathelement location="${lib}/jasper-runtime.jar" />
|
<pathelement location="${lib}/jasper-runtime.jar" />
|
||||||
<pathelement location="${lib}/commons-logging.jar" />
|
<pathelement location="${lib}/commons-logging.jar" />
|
||||||
<!-- jasper-el.jar only present for debian builds -->
|
<pathelement location="${lib}/jetty-util.jar" />
|
||||||
<pathelement location="${lib}/jasper-el.jar" />
|
|
||||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||||
|
<pathelement location="../../addressbook/dist/addressbook.jar" />
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<property name="javac.compilerargs" value="" />
|
<property name="javac.compilerargs" value="" />
|
||||||
|
@ -314,6 +314,9 @@ public class AddressbookBean extends BaseBean
|
|||||||
}
|
}
|
||||||
if (action.equals(_t("Delete Entry")))
|
if (action.equals(_t("Delete Entry")))
|
||||||
search = null;
|
search = null;
|
||||||
|
} else if (action.equals(_t("Add Alternate"))) {
|
||||||
|
// button won't be in UI
|
||||||
|
message = "Unsupported";
|
||||||
}
|
}
|
||||||
if( changed ) {
|
if( changed ) {
|
||||||
try {
|
try {
|
||||||
|
@ -231,7 +231,7 @@ public class NamingServiceBean extends AddressbookBean
|
|||||||
if (_context.getBooleanProperty(PROP_PW_ENABLE) ||
|
if (_context.getBooleanProperty(PROP_PW_ENABLE) ||
|
||||||
(serial != null && serial.equals(lastSerial))) {
|
(serial != null && serial.equals(lastSerial))) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
if (action.equals(_t("Add")) || action.equals(_t("Replace"))) {
|
if (action.equals(_t("Add")) || action.equals(_t("Replace")) || action.equals(_t("Add Alternate"))) {
|
||||||
if(hostname != null && destination != null) {
|
if(hostname != null && destination != null) {
|
||||||
try {
|
try {
|
||||||
// throws IAE with translated message
|
// throws IAE with translated message
|
||||||
@ -243,20 +243,38 @@ public class NamingServiceBean extends AddressbookBean
|
|||||||
Destination oldDest = getNamingService().lookup(host, nsOptions, outProperties);
|
Destination oldDest = getNamingService().lookup(host, nsOptions, outProperties);
|
||||||
if (oldDest != null && destination.equals(oldDest.toBase64())) {
|
if (oldDest != null && destination.equals(oldDest.toBase64())) {
|
||||||
message = _t("Host name {0} is already in address book, unchanged.", displayHost);
|
message = _t("Host name {0} is already in address book, unchanged.", displayHost);
|
||||||
} else if (oldDest != null && !action.equals(_t("Replace"))) {
|
} else if (oldDest == null && action.equals(_t("Add Alternate"))) {
|
||||||
|
message = _t("Host name {0} is not in the address book.", displayHost);
|
||||||
|
} else if (oldDest != null && action.equals(_t("Add"))) {
|
||||||
message = _t("Host name {0} is already in address book with a different destination. Click \"Replace\" to overwrite.", displayHost);
|
message = _t("Host name {0} is already in address book with a different destination. Click \"Replace\" to overwrite.", displayHost);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Destination dest = new Destination(destination);
|
Destination dest = new Destination(destination);
|
||||||
if (oldDest != null) {
|
if (oldDest != null) {
|
||||||
nsOptions.putAll(outProperties);
|
nsOptions.putAll(outProperties);
|
||||||
nsOptions.setProperty("m", Long.toString(_context.clock().now()));
|
String now = Long.toString(_context.clock().now());
|
||||||
|
if (action.equals(_t("Add Alternate")))
|
||||||
|
nsOptions.setProperty("a", now);
|
||||||
|
else
|
||||||
|
nsOptions.setProperty("m", now);
|
||||||
}
|
}
|
||||||
nsOptions.setProperty("s", _t("Manually added via SusiDNS"));
|
nsOptions.setProperty("s", _t("Manually added via SusiDNS"));
|
||||||
boolean success = getNamingService().put(host, dest, nsOptions);
|
boolean success;
|
||||||
|
if (action.equals(_t("Add Alternate"))) {
|
||||||
|
// check all for dups
|
||||||
|
List<Destination> all = getNamingService().lookupAll(host);
|
||||||
|
if (all == null || !all.contains(dest)) {
|
||||||
|
success = getNamingService().addDestination(host, dest, nsOptions);
|
||||||
|
} else {
|
||||||
|
// will get generic message below
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
success = getNamingService().put(host, dest, nsOptions);
|
||||||
|
}
|
||||||
if (success) {
|
if (success) {
|
||||||
changed = true;
|
changed = true;
|
||||||
if (oldDest == null)
|
if (oldDest == null || action.equals(_t("Add Alternate")))
|
||||||
message = _t("Destination added for {0}.", displayHost);
|
message = _t("Destination added for {0}.", displayHost);
|
||||||
else
|
else
|
||||||
message = _t("Destination changed for {0}.", displayHost);
|
message = _t("Destination changed for {0}.", displayHost);
|
||||||
@ -285,8 +303,21 @@ public class NamingServiceBean extends AddressbookBean
|
|||||||
} else if (action.equals(_t("Delete Selected")) || action.equals(_t("Delete Entry"))) {
|
} else if (action.equals(_t("Delete Selected")) || action.equals(_t("Delete Entry"))) {
|
||||||
String name = null;
|
String name = null;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
|
Destination matchDest = null;
|
||||||
|
if (action.equals(_t("Delete Entry"))) {
|
||||||
|
// remove specified dest only in case there is more than one
|
||||||
|
if (destination != null) {
|
||||||
|
try {
|
||||||
|
matchDest = new Destination(destination);
|
||||||
|
} catch (DataFormatException dfe) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (String n : deletionMarks) {
|
for (String n : deletionMarks) {
|
||||||
boolean success = getNamingService().remove(n, nsOptions);
|
boolean success;
|
||||||
|
if (matchDest != null)
|
||||||
|
success = getNamingService().remove(n, matchDest, nsOptions);
|
||||||
|
else
|
||||||
|
success = getNamingService().remove(n, nsOptions);
|
||||||
String uni = AddressBean.toUnicode(n);
|
String uni = AddressBean.toUnicode(n);
|
||||||
String displayHost = uni.equals(n) ? n : uni + " (" + n + ')';
|
String displayHost = uni.equals(n) ? n : uni + " (" + n + ')';
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -19,11 +19,10 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.i2p.addressbook;
|
package net.i2p.addressbook.servlet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
@ -31,25 +30,29 @@ import javax.servlet.http.HttpServlet;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
//import net.i2p.addressbook.DaemonThread;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper for addressbook to allow it to be started as a web application.
|
* A wrapper for addressbook to allow it to be started as a web application.
|
||||||
*
|
*
|
||||||
* This was a GenericServlet, we make it an HttpServlet solely to provide a hook
|
* This was a GenericServlet, we make it an HttpServlet solely to provide a
|
||||||
* for SusiDNS to wake us up when the subscription list changes.
|
* simple page to display status.
|
||||||
*
|
*
|
||||||
|
* @since 0.9.30 moved from addressbook to SusiDNS
|
||||||
* @author Ragnarok
|
* @author Ragnarok
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Servlet extends HttpServlet {
|
public class Servlet extends HttpServlet {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private transient DaemonThread thread;
|
private transient Thread thread;
|
||||||
//private String nonce;
|
//private String nonce;
|
||||||
//private static final String PROP_NONCE = "addressbook.nonce";
|
//private static final String PROP_NONCE = "addressbook.nonce";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hack to allow susidns to kick the daemon when the subscription list changes.
|
* Simple output to verify that the addressbook servlet is running.
|
||||||
* URL must be /addressbook/ with wakeup param set, and nonce param set from system property.
|
|
||||||
*
|
*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
* see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||||
@ -70,6 +73,7 @@ public class Servlet extends HttpServlet {
|
|||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void init(ServletConfig config) {
|
public void init(ServletConfig config) {
|
||||||
try {
|
try {
|
||||||
@ -82,17 +86,39 @@ public class Servlet extends HttpServlet {
|
|||||||
//System.setProperty(PROP_NONCE, this.nonce);
|
//System.setProperty(PROP_NONCE, this.nonce);
|
||||||
String[] args = new String[1];
|
String[] args = new String[1];
|
||||||
args[0] = config.getInitParameter("home");
|
args[0] = config.getInitParameter("home");
|
||||||
this.thread = new DaemonThread(args);
|
try {
|
||||||
this.thread.setDaemon(true);
|
ClassLoader cl = getServletContext().getClassLoader();
|
||||||
this.thread.setName("Addressbook");
|
Class cls = Class.forName("net.i2p.addressbook.DaemonThread", true, cl);
|
||||||
this.thread.start();
|
// We do it this way so that if we can't find addressbook,
|
||||||
|
// the whole thing doesn't die.
|
||||||
|
// We do add addressbook.jar in WebAppConfiguration,
|
||||||
|
// so this is just in case.
|
||||||
|
//Thread t = new DaemonThread(args);
|
||||||
|
Thread t = (Thread) cls.getConstructor(String[].class).newInstance((Object)args);
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.setName("Addressbook");
|
||||||
|
t.start();
|
||||||
|
this.thread = t;
|
||||||
//System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
//System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||||
//System.out.println("INFO: config root under " + args[0]);
|
//System.out.println("INFO: config root under " + args[0]);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// addressbook.jar may not be in the classpath
|
||||||
|
I2PAppContext.getGlobalContext().logManager().getLog(Servlet.class).logAlways(Log.WARN, "Addressbook thread not started: " + t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
this.thread.halt();
|
if (this.thread != null) {
|
||||||
|
//((DaemonThread)this.thread).halt();
|
||||||
|
try {
|
||||||
|
ClassLoader cl = getServletContext().getClassLoader();
|
||||||
|
Class<?> cls = Class.forName("net.i2p.addressbook.DaemonThread", true, cl);
|
||||||
|
Object t = cls.cast(this.thread);
|
||||||
|
cls.getDeclaredMethod("halt").invoke(t);
|
||||||
|
} catch (Throwable t) {}
|
||||||
|
}
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
The servlet that starts the addressbook DaemonThread.
|
||||||
|
Moved from addressbook to SusiDNS in 0.9.30.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user