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.ko = installer/resources/locale-man/man_ko.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_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
|
||||
|
||||
[main]
|
||||
|
@@ -212,12 +212,11 @@ Applications:
|
||||
Zxing 3.3.0:
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
Jetty 8.1.21.v20160908:
|
||||
Jetty 9.2.21.v20170120:
|
||||
See licenses/ABOUT-Jetty.html
|
||||
See licenses/NOTICE-Jetty.html
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/LICENSE-ECLIPSE-1.0.html
|
||||
See licenses/NOTICE-Commons-Logging.txt
|
||||
|
||||
JRobin 1.6.0-1:
|
||||
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
||||
@@ -284,7 +283,7 @@ Applications:
|
||||
Bundles systray4j-2.4.1:
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
Tomcat 6.0.48:
|
||||
Tomcat 8.0.33:
|
||||
Copyright 1999-2016 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="addressbook" default="war" basedir=".">
|
||||
<project name="addressbook" default="all" basedir=".">
|
||||
|
||||
<property name="src" value="java/src"/>
|
||||
<property name="build" value="build"/>
|
||||
@@ -8,6 +8,8 @@
|
||||
<property name="war" value="addressbook.war"/>
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.7" />
|
||||
|
||||
<target name="all" depends="jar, emptyWar"/>
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="${build}"/>
|
||||
@@ -36,24 +38,10 @@
|
||||
</depend>
|
||||
</target>
|
||||
|
||||
<target name="dependServlet" if="depend.available">
|
||||
<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">
|
||||
<target name="compile" depends="init, depend, warUpToDate">
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
includeAntRuntime="false"
|
||||
srcdir="${src}" destdir="${build}"
|
||||
excludes="net/i2p/addressbook/Servlet.java">
|
||||
srcdir="${src}" destdir="${build}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
<pathelement location="../../core/java/build/i2p.jar" />
|
||||
@@ -61,20 +49,6 @@
|
||||
</javac>
|
||||
</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">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
@@ -91,29 +65,14 @@
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="war" depends="compileServlet, changes, warUpToDate" unless="war.uptodate">
|
||||
<mkdir dir="${dist}/tmp"/>
|
||||
<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>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<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>
|
||||
</war>
|
||||
<delete dir="${dist}/tmp"/>
|
||||
</target>
|
||||
|
||||
<target name="emptyWar" depends="init">
|
||||
<jar destfile="${dist}/${war}" >
|
||||
<manifest>
|
||||
<attribute name="Note" value="Intentionally empty" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="warUpToDate">
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${war}">
|
||||
|
@@ -43,13 +43,13 @@ import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Main class of addressbook. Performs updates, and runs the main loop.
|
||||
* As of 0.9.30, package private, run with DaemonThread.
|
||||
*
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class Daemon {
|
||||
class Daemon {
|
||||
public static final String VERSION = "2.0.4";
|
||||
private static final Daemon _instance = new Daemon();
|
||||
private volatile boolean _running;
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String DEFAULT_SUB = "http://i2p-projekt.i2p/hosts.txt";
|
||||
@@ -787,14 +787,15 @@ public class Daemon {
|
||||
* others are ignored.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Daemon daemon = new Daemon();
|
||||
if (args != null && args.length > 0 && args[0].equals("test"))
|
||||
_instance.test(args);
|
||||
daemon.test(args);
|
||||
else
|
||||
_instance.run(args);
|
||||
daemon.run(args);
|
||||
}
|
||||
|
||||
/** @since 0.9.26 */
|
||||
private static void test(String[] args) {
|
||||
public static void test(String[] args) {
|
||||
Properties ctxProps = new Properties();
|
||||
String PROP_FORCE = "i2p.naming.blockfile.writeInAppContext";
|
||||
ctxProps.setProperty(PROP_FORCE, "true");
|
||||
@@ -875,14 +876,14 @@ public class Daemon {
|
||||
* Call this to get the addressbook to reread its config and
|
||||
* refetch its subscriptions.
|
||||
*/
|
||||
public static void wakeup() {
|
||||
synchronized (_instance) {
|
||||
_instance.notifyAll();
|
||||
public void wakeup() {
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop() {
|
||||
_instance._running = false;
|
||||
public void stop() {
|
||||
_running = false;
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import net.i2p.util.I2PAppThread;
|
||||
public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
||||
|
||||
private final String[] args;
|
||||
private final Daemon daemon;
|
||||
|
||||
/**
|
||||
* Construct a DaemonThread with the command line arguments args.
|
||||
@@ -44,6 +45,7 @@ public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
||||
*/
|
||||
public DaemonThread(String[] args) {
|
||||
this.args = args;
|
||||
daemon = new Daemon();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -56,18 +58,28 @@ public class DaemonThread extends I2PAppThread implements NamingServiceUpdater {
|
||||
//} catch (InterruptedException exp) {
|
||||
//}
|
||||
I2PAppContext.getGlobalContext().namingService().registerUpdater(this);
|
||||
Daemon.main(this.args);
|
||||
I2PAppContext.getGlobalContext().namingService().unregisterUpdater(this);
|
||||
try {
|
||||
if (args != null && args.length > 0 && args[0].equals("test"))
|
||||
daemon.test(args);
|
||||
else
|
||||
daemon.run(args);
|
||||
} finally {
|
||||
I2PAppContext.getGlobalContext().namingService().unregisterUpdater(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void halt() {
|
||||
Daemon.stop();
|
||||
daemon.stop();
|
||||
interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* The NamingServiceUpdater interface
|
||||
* @param options ignored
|
||||
* The NamingServiceUpdater interface.
|
||||
* 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
|
||||
*/
|
||||
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 List<String> _openTrackers;
|
||||
private DHT _dht;
|
||||
private long _startedTime;
|
||||
|
||||
private static final int EEPGET_CONNECT_TIMEOUT = 45*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)
|
||||
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
|
||||
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
||||
if (_manager != null)
|
||||
_startedTime = _context.clock().now();
|
||||
_connecting = false;
|
||||
}
|
||||
if (_shouldUseDHT && _manager != null && _dht == null)
|
||||
@@ -295,6 +298,7 @@ public class I2PSnarkUtil {
|
||||
_dht.stop();
|
||||
_dht = null;
|
||||
}
|
||||
_startedTime = 0;
|
||||
I2PSocketManager mgr = _manager;
|
||||
// FIXME this can cause race NPEs elsewhere
|
||||
_manager = null;
|
||||
@@ -310,6 +314,16 @@ public class I2PSnarkUtil {
|
||||
_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 */
|
||||
I2PSocket connect(PeerID peer) throws IOException {
|
||||
I2PSocketManager mgr = _manager;
|
||||
|
@@ -89,6 +89,7 @@ public class Peer implements Comparable<Peer>
|
||||
*/
|
||||
//private static final long OPTION_AZMP = 0x1000000000000000l;
|
||||
private long options;
|
||||
private final boolean _isIncoming;
|
||||
|
||||
/**
|
||||
* Outgoing connection.
|
||||
@@ -103,6 +104,7 @@ public class Peer implements Comparable<Peer>
|
||||
this.infohash = infohash;
|
||||
this.metainfo = metainfo;
|
||||
_id = __id.incrementAndGet();
|
||||
_isIncoming = false;
|
||||
//_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();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_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.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
@@ -237,8 +238,10 @@ public class Snark
|
||||
private volatile boolean _autoStoppable;
|
||||
// String indicating main activity
|
||||
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
|
||||
@@ -542,6 +545,7 @@ public class Snark
|
||||
starting = true;
|
||||
try {
|
||||
x_startTorrent();
|
||||
_startedTime = _util.getContext().clock().now();
|
||||
} finally {
|
||||
starting = false;
|
||||
}
|
||||
@@ -633,16 +637,17 @@ public class Snark
|
||||
if (st != null) {
|
||||
// TODO: Cache the config-in-mem to compare vs config-on-disk
|
||||
// (needed for auto-save to not double-save in some cases)
|
||||
//boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
|
||||
boolean changed = true;
|
||||
if (changed && completeListener != null)
|
||||
completeListener.updateStatus(this);
|
||||
long nowUploaded = getUploaded();
|
||||
boolean changed = storage.isChanged() || nowUploaded != savedUploaded;
|
||||
try {
|
||||
storage.close();
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Error closing " + torrent);
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
savedUploaded = nowUploaded;
|
||||
if (changed && completeListener != null)
|
||||
completeListener.updateStatus(this);
|
||||
}
|
||||
if (fast)
|
||||
// HACK: See above if(!fast)
|
||||
@@ -1285,8 +1290,12 @@ public class Snark
|
||||
|
||||
allChecked = true;
|
||||
checking = false;
|
||||
if (storage.isChanged() && completeListener != null)
|
||||
if (storage.isChanged() && completeListener != null) {
|
||||
completeListener.updateStatus(this);
|
||||
// this saved the status, so reset the variables
|
||||
storage.clearChanged();
|
||||
savedUploaded = getUploaded();
|
||||
}
|
||||
}
|
||||
|
||||
public void storageCompleted(Storage storage)
|
||||
@@ -1295,8 +1304,12 @@ public class Snark
|
||||
_log.info("Completely received " + torrent);
|
||||
//storage.close();
|
||||
//System.out.println("Completely received: " + torrent);
|
||||
if (completeListener != null)
|
||||
if (completeListener != null) {
|
||||
completeListener.torrentComplete(this);
|
||||
// this saved the status, so reset the variables
|
||||
savedUploaded = getUploaded();
|
||||
storage.clearChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setWantedPieces(Storage storage)
|
||||
@@ -1364,4 +1377,23 @@ public class Snark
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
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 net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import net.i2p.crypto.SHA1Hash;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.data.Base64;
|
||||
@@ -51,7 +53,7 @@ import org.klomp.snark.dht.KRPC;
|
||||
/**
|
||||
* 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.
|
||||
@@ -246,6 +248,13 @@ public class SnarkManager implements CompleteListener {
|
||||
*/
|
||||
public void start() {
|
||||
_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();
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
||||
@@ -315,6 +324,12 @@ public class SnarkManager implements CompleteListener {
|
||||
_connectionAcceptor.halt();
|
||||
_idleChecker.cancel();
|
||||
stopAllTorrents(true);
|
||||
if ("i2psnark".equals(_contextName)) {
|
||||
// only if default instance
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
cmgr.unregister(this);
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Snark stop() end");
|
||||
}
|
||||
@@ -322,6 +337,46 @@ public class SnarkManager implements CompleteListener {
|
||||
/** @since 0.9.1 */
|
||||
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 */
|
||||
public I2PSnarkUtil util() { return _util; }
|
||||
|
||||
@@ -440,6 +495,14 @@ public class SnarkManager implements CompleteListener {
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* For RPC
|
||||
* @since 0.9.30
|
||||
*/
|
||||
public File getConfigDir() {
|
||||
return _configDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the old flat config file to the new config dir
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
* 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
|
||||
* @throws RuntimeException via Snark.fatal()
|
||||
* @return success
|
||||
@@ -1542,10 +1605,18 @@ public class SnarkManager implements CompleteListener {
|
||||
if (snark != null) {
|
||||
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
||||
return false;
|
||||
} else {
|
||||
} else if (bitfield != null) {
|
||||
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
|
||||
}
|
||||
// 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 {
|
||||
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
|
||||
// hold the lock for a long time
|
||||
|
@@ -305,6 +305,14 @@ public class Storage implements Closeable
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the storage changed variable
|
||||
* @since 0.9.30
|
||||
*/
|
||||
void clearChanged() {
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* File checking in progress.
|
||||
* @since 0.9.3
|
||||
|
@@ -106,11 +106,11 @@ class NodeInfo extends SimpleDataStructure {
|
||||
if (parts.length != 4)
|
||||
throw new DataFormatException("Bad format");
|
||||
byte[] nid = Base64.decode(parts[0]);
|
||||
if (nid == null)
|
||||
if (nid == null || nid.length != NID.HASH_LENGTH)
|
||||
throw new DataFormatException("Bad NID");
|
||||
nID = new NID(nid);
|
||||
byte[] h = Base64.decode(parts[1]);
|
||||
if (h == null)
|
||||
if (h == null || h.length != Hash.HASH_LENGTH)
|
||||
throw new DataFormatException("Bad hash");
|
||||
//hash = new Hash(h);
|
||||
hash = Hash.create(h);
|
||||
|
@@ -1803,6 +1803,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
client = "Vuze" + getAzVersion(pid.getID());
|
||||
else if ("CwsL".equals(ch))
|
||||
client = "I2PSnarkXL";
|
||||
else if ("LVhE".equals(ch))
|
||||
client = "XD" + getAzVersion(pid.getID());
|
||||
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
|
||||
client = "Robert" + getRobtVersion(pid.getID());
|
||||
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
||||
|
@@ -22,15 +22,24 @@
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Call name="addConnector">
|
||||
<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="port">8002</Set>
|
||||
<Set name="maxIdleTime">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>
|
||||
<Set name="idleTimeout">600000</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
@@ -96,7 +105,7 @@
|
||||
<Ref id="DeploymentManager">
|
||||
<Call name="addAppProvider">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.deploy.providers.ContextProvider">
|
||||
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<Set name="monitoredDirName">./contexts</Set>
|
||||
<Set name="scanInterval">0</Set>
|
||||
</New>
|
||||
|
@@ -4,9 +4,24 @@ java -jar i2psnark.jar
|
||||
|
||||
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
|
||||
(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
|
||||
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>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.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" />
|
||||
<!-- tomcat-api.jar only present for debian builds -->
|
||||
<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/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||
<pathelement location="build/i2ptunnel.jar" />
|
||||
<pathelement location="build/temp-beans.jar" />
|
||||
@@ -309,12 +312,14 @@
|
||||
<classpath>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.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" />
|
||||
<!-- tomcat-api.jar only present for debian builds -->
|
||||
<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/tomcat-util.jar" />
|
||||
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.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
|
||||
*/
|
||||
protected static synchronized I2PSession addSubsession(I2PTunnel tunnel) {
|
||||
|
@@ -204,7 +204,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
"Proxy-Connection: close\r\n"+
|
||||
"\r\n" +
|
||||
"<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";
|
||||
|
||||
/**
|
||||
|
@@ -210,13 +210,13 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
socket.reset();
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error while receiving the new IRC Connection", ex);
|
||||
} catch (OutOfMemoryError oom) {
|
||||
try {
|
||||
socket.close();
|
||||
socket.reset();
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("OOM in IRC server", oom);
|
||||
|
@@ -18,6 +18,7 @@ import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -29,12 +30,14 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
@@ -67,6 +70,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
private static final boolean DEFAULT_USE_POOL = true;
|
||||
public static final String PROP_USE_SSL = "useSSL";
|
||||
public static final String PROP_UNIQUE_LOCAL = "enableUniqueLocal";
|
||||
/** @since 0.9.30 */
|
||||
public static final String PROP_ALT_PKF = "altPrivKeyFile";
|
||||
/** apparently unused */
|
||||
protected static volatile long __serverId = 0;
|
||||
/** 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);
|
||||
rv.setName("I2PTunnel Server");
|
||||
getTunnel().addSession(rv.getSession());
|
||||
String alt = props.getProperty(PROP_ALT_PKF);
|
||||
if (alt != null)
|
||||
addSubsession(rv, alt);
|
||||
return rv;
|
||||
} catch (I2PSessionException 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;
|
||||
@@ -238,6 +284,22 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
while (sockMgr.getSession().isClosed()) {
|
||||
try {
|
||||
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) {
|
||||
// try to make this error sensible as it will happen...
|
||||
String portNum = getTunnel().port;
|
||||
@@ -618,7 +680,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
socket.reset();
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
|
||||
|
@@ -3,6 +3,7 @@ package net.i2p.i2ptunnel;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@@ -16,12 +17,22 @@ import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.crypto.KeyGenerator;
|
||||
import net.i2p.crypto.SigType;
|
||||
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.util.FileUtil;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.RandomSource;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
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_LOW_TAGS = PFX_OPTION + "crypto.lowTagThreshold";
|
||||
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 */
|
||||
public static final String TYPE_CONNECT = "connectclient";
|
||||
@@ -106,7 +119,7 @@ public class TunnelController implements Logging {
|
||||
*/
|
||||
public static final SigType PREFERRED_SIGTYPE;
|
||||
static {
|
||||
if (SystemVersion.isARM() || SystemVersion.isGNU() || SystemVersion.isAndroid()) {
|
||||
if (SystemVersion.isGNU() || SystemVersion.isAndroid()) {
|
||||
if (SigType.ECDSA_SHA256_P256.isAvailable())
|
||||
PREFERRED_SIGTYPE = SigType.ECDSA_SHA256_P256;
|
||||
else
|
||||
@@ -146,8 +159,13 @@ public class TunnelController implements Logging {
|
||||
setConfig(config, prefix);
|
||||
_messages = new ArrayList<String>(4);
|
||||
boolean keyOK = true;
|
||||
if (createKey && (getType().endsWith("server") || getPersistentClientKey()))
|
||||
if (createKey && (!isClient() || getPersistentClientKey())) {
|
||||
keyOK = createPrivateKey();
|
||||
if (keyOK && !isClient() && !getType().equals(TYPE_STREAMR_SERVER)) {
|
||||
// check rv?
|
||||
createAltPrivateKey();
|
||||
}
|
||||
}
|
||||
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
|
||||
}
|
||||
|
||||
@@ -186,7 +204,7 @@ public class TunnelController implements Logging {
|
||||
String destStr = dest.toBase64();
|
||||
log("Private key created and saved in " + keyFile.getAbsolutePath());
|
||||
log("You should backup this file in a secure place.");
|
||||
log("New destination: " + destStr);
|
||||
log("New alternate destination: " + destStr);
|
||||
String b32 = dest.toBase32();
|
||||
log("Base32: " + b32);
|
||||
File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR);
|
||||
@@ -214,6 +232,101 @@ public class TunnelController implements Logging {
|
||||
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() {
|
||||
synchronized (this) {
|
||||
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.
|
||||
// Or should we take it out of the constructor completely?
|
||||
if (type.endsWith("server") || getPersistentClientKey()) {
|
||||
if (!isClient() || getPersistentClientKey()) {
|
||||
boolean ok = createPrivateKey();
|
||||
if (!ok) {
|
||||
changeState(TunnelState.STOPPED);
|
||||
log("Failed to start tunnel " + getName() + " as the private key file could not be created");
|
||||
return;
|
||||
}
|
||||
if (!isClient() && !getType().equals(TYPE_STREAMR_SERVER)) {
|
||||
// check rv?
|
||||
createAltPrivateKey();
|
||||
}
|
||||
}
|
||||
setI2CPOptions();
|
||||
setSessionOptions();
|
||||
@@ -641,6 +758,7 @@ public class TunnelController implements Logging {
|
||||
props.setProperty(key, val);
|
||||
}
|
||||
}
|
||||
Properties oldConfig = _config;
|
||||
_config = props;
|
||||
|
||||
// Set up some per-type defaults
|
||||
@@ -685,6 +803,15 @@ public class TunnelController implements Logging {
|
||||
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
|
||||
Collection<I2PSession> sessions = getAllSessions();
|
||||
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
|
||||
*/
|
||||
@@ -797,7 +935,25 @@ public class TunnelController implements Logging {
|
||||
* @since 0.9.17
|
||||
*/
|
||||
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)
|
||||
return null;
|
||||
f = f.trim();
|
||||
|
@@ -119,7 +119,7 @@ public class I2PTunnelDCCServer extends I2PTunnelServer {
|
||||
_active.put(Integer.valueOf(myPort), local);
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
socket.reset();
|
||||
} catch (IOException ioe) {}
|
||||
_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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just calls close()
|
||||
* @since 0.9.30
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
close();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return socket.isClosed();
|
||||
}
|
||||
|
@@ -264,14 +264,23 @@ public class GeneralHelper {
|
||||
return (tun != null && tun.getSpoofedHost() != null) ? tun.getSpoofedHost() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return path, non-null, non-empty
|
||||
*/
|
||||
public String getPrivateKeyFile(int tunnel) {
|
||||
return getPrivateKeyFile(_group, tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return path, non-null, non-empty
|
||||
*/
|
||||
public String getPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) {
|
||||
TunnelController tun = getController(tcg, tunnel);
|
||||
if (tun != null && tun.getPrivKeyFile() != null)
|
||||
return tun.getPrivKeyFile();
|
||||
if (tun != null) {
|
||||
String rv = tun.getPrivKeyFile();
|
||||
if (rv != null)
|
||||
return rv;
|
||||
}
|
||||
if (tunnel < 0)
|
||||
tunnel = tcg == null ? 999 : tcg.getControllers().size();
|
||||
String rv = "i2ptunnel" + tunnel + "-privKeys.dat";
|
||||
@@ -284,6 +293,28 @@ public class GeneralHelper {
|
||||
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) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
@@ -357,6 +388,29 @@ public class GeneralHelper {
|
||||
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) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
return tun != null ? tun.getStartOnLoad() : false;
|
||||
|
@@ -161,6 +161,16 @@ public class TunnelConfig {
|
||||
public String getPrivKeyFile() {
|
||||
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
|
||||
* 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_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
||||
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[] = {
|
||||
I2PTunnelHTTPServer.OPT_POST_WINDOW,
|
||||
|
@@ -70,6 +70,14 @@ public class EditBean extends IndexBean {
|
||||
public String getPrivateKeyFile(int 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) {
|
||||
|
@@ -488,6 +488,39 @@ public class IndexBean {
|
||||
return d.toBase32();
|
||||
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
|
||||
@@ -613,10 +646,20 @@ public class IndexBean {
|
||||
public void setSpoofedHost(String host) {
|
||||
_config.setSpoofedHost(host);
|
||||
}
|
||||
|
||||
/** What filename is this server tunnel's private keys stored in */
|
||||
public void setPrivKeyFile(String 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),
|
||||
* we really do want to stop and remove the tunnel.
|
||||
|
@@ -735,8 +735,9 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
</div>
|
||||
<% **********************/ %>
|
||||
|
||||
<% if (true /* editBean.isAdvanced() */ ) {
|
||||
int currentSigType = editBean.getSigType(curTunnel, tunnelType);
|
||||
<%
|
||||
int currentSigType = editBean.getSigType(curTunnel, tunnelType);
|
||||
if (true /* editBean.isAdvanced() */ ) {
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
@@ -779,6 +780,50 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
|
||||
<% } // 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>
|
||||
<th colspan="2">
|
||||
<%=intl._t("Custom options")%>
|
||||
|
@@ -91,6 +91,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
}
|
||||
%>
|
||||
|
||||
<!--
|
||||
<tr>
|
||||
<th>
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
|
||||
<%
|
||||
if (b64 == null || b64.length() < 516) {
|
||||
@@ -307,12 +309,40 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
</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 {
|
||||
%><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new destination.")%>
|
||||
<%=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,
|
||||
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,
|
||||
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! -->
|
||||
<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.sha1" value="9780e99e765fd7b9bb1aac8ba2bba374ac039764" />
|
||||
<property name="jetty.sha1" value="3dcd4f66cc3f72800a2ee53fecf7b3f9d3f23eb2" />
|
||||
<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="javac.compilerargs" value="" />
|
||||
<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" />
|
||||
|
||||
@@ -41,7 +40,7 @@
|
||||
<target name="ensureJettylib1" >
|
||||
<condition property="jetty.zip.extracted" >
|
||||
<or>
|
||||
<istrue value="${with-libjetty8-java}" />
|
||||
<istrue value="${with-libjetty9-java}" />
|
||||
<available file="${jetty.base}" type="dir" />
|
||||
</or>
|
||||
</condition>
|
||||
@@ -53,7 +52,7 @@
|
||||
</condition>
|
||||
<condition property="verified.already" >
|
||||
<or>
|
||||
<istrue value="${with-libjetty8-java}" />
|
||||
<istrue value="${with-libjetty9-java}" />
|
||||
<istrue value="${jetty.zip.extracted}" />
|
||||
<and>
|
||||
<available file="${jetty.filename}" />
|
||||
@@ -120,10 +119,17 @@
|
||||
</target>
|
||||
|
||||
<!-- 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 -->
|
||||
<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
|
||||
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.
|
||||
@@ -166,43 +172,29 @@
|
||||
<attribute name="Note" value="Intentionally empty" />
|
||||
</manifest>
|
||||
</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" >
|
||||
<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/jsp/javax.servlet.jsp-2.2.0.v201112011158.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" />
|
||||
<!--
|
||||
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>
|
||||
<!--
|
||||
<delete file="jetty.tar" />
|
||||
<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>
|
||||
|
||||
<!-- 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.
|
||||
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="copyTomcatLib1" unless="${with-libservlet2.5-java}" >
|
||||
<target name="copyTomcatLib1" >
|
||||
<condition property="with-libtomcat-java" >
|
||||
<or>
|
||||
<istrue value="${with-libtomcat6-java}" />
|
||||
@@ -233,34 +225,47 @@
|
||||
|
||||
|
||||
<target name="copyTomcatLib2" unless="${with-libtomcat-java}" >
|
||||
<!-- EL libs.
|
||||
<!-- EL API and compiler libs.
|
||||
Tomcat 6 has EL 2.1.
|
||||
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
|
||||
2.2 is backwards-compatible with 2.1.
|
||||
-->
|
||||
<jar destfile="jettylib/commons-el.jar" duplicate="preserve" filesetmanifest="merge" >
|
||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper-el.jar" />
|
||||
<zipfileset excludes="META-INF/**/*" src="${tomcat.lib}/el-api.jar" />
|
||||
<!-- the javax.el API, AND the com.sun.el parser -->
|
||||
<!-- actually from jetty9, not tomcat8... this will fail unless we have the jetty files also -->
|
||||
<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 destfile="jettylib/jasper-runtime.jar" filesetmanifest="merge" >
|
||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper.jar" />
|
||||
<zipfileset src="${tomcat2.lib.small}/tomcat-coyote-util.jar" />
|
||||
<!-- actually from jetty9, not tomcat8... this will fail unless we have the jetty files also -->
|
||||
<jar destfile="jettylib/jasper-runtime.jar" >
|
||||
<!--
|
||||
Jetty version
|
||||
<zipfileset src="${jetty.base}/lib/jsp/javax.servlet.jsp-2.3.2.jar"/>
|
||||
To be included in jasper-runtime.jar?
|
||||
Server complains "NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet" even with this included (but it still works).
|
||||
The following file has the class, but /usr/share/java/jetty8-jsp.jar is empty
|
||||
We don't use this one, because we want to be consistent with Debian builds that
|
||||
must use Apache (aka libtomcat8).
|
||||
<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" />
|
||||
-->
|
||||
<!-- 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/javax.servlet.jar" duplicate="preserve" filesetmanifest="mergewithoutmain" >
|
||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/servlet-api.jar" />
|
||||
<zipfileset excludes="META-INF/**/*" src="${tomcat.lib}/jsp-api.jar" />
|
||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-api.jar" />
|
||||
<zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-util.jar" />
|
||||
</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
|
||||
-->
|
||||
|
||||
<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>
|
||||
</target>
|
||||
|
||||
|
@@ -263,4 +263,11 @@ public class I2PLogger implements Logger
|
||||
public String getName() {
|
||||
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 org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
@@ -81,7 +80,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
private transient OutputStream _out;
|
||||
private transient OutputStream _fileOut;
|
||||
private transient DateCache _logDateCache;
|
||||
private transient PathMap _ignorePathMap;
|
||||
private transient PathMap<String> _ignorePathMap;
|
||||
private transient Writer _writer;
|
||||
private transient ArrayList<Utf8StringBuilder> _buffers;
|
||||
private transient char[] _copy;
|
||||
@@ -286,7 +285,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
String addr = null;
|
||||
if (_preferProxiedForAddress)
|
||||
{
|
||||
addr = request.getHeader(HttpHeaders.X_FORWARDED_FOR);
|
||||
addr = request.getHeader("X-Forwarded-For");
|
||||
}
|
||||
|
||||
if (addr == null) {
|
||||
@@ -310,7 +309,9 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
if (_logDateCache!=null)
|
||||
buf.append(_logDateCache.format(request.getTimeStamp()));
|
||||
else
|
||||
buf.append(request.getTimeStampBuffer().toString());
|
||||
//buf.append(request.getTimeStampBuffer().toString());
|
||||
// TODO SimpleDateFormat or something
|
||||
buf.append(request.getTimeStamp());
|
||||
|
||||
buf.append("] \"");
|
||||
buf.append(request.getMethod());
|
||||
@@ -358,7 +359,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
{
|
||||
synchronized(_writer)
|
||||
{
|
||||
buf.append(StringUtil.__LINE_SEPARATOR);
|
||||
buf.append(System.getProperty("line.separator", "\n"));
|
||||
int l=buf.length();
|
||||
if (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(StringUtil.__LINE_SEPARATOR);
|
||||
_writer.write(System.getProperty("line.separator", "\n"));
|
||||
_writer.flush();
|
||||
}
|
||||
}
|
||||
@@ -429,7 +430,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
Response response,
|
||||
Writer writer) throws IOException
|
||||
{
|
||||
String referer = request.getHeader(HttpHeaders.REFERER);
|
||||
String referer = request.getHeader("Referer");
|
||||
if (referer == null)
|
||||
writer.write("\"-\" ");
|
||||
else
|
||||
@@ -439,7 +440,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
writer.write("\" ");
|
||||
}
|
||||
|
||||
String agent = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
String agent = request.getHeader("User-Agent");
|
||||
if (agent == null)
|
||||
writer.write("\"-\" ");
|
||||
else
|
||||
@@ -455,8 +456,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
{
|
||||
if (_logDateFormat!=null)
|
||||
{
|
||||
_logDateCache = new DateCache(_logDateFormat, _logLocale);
|
||||
_logDateCache.setTimeZoneID(_logTimeZone);
|
||||
_logDateCache = new DateCache(_logDateFormat, _logLocale, _logTimeZone);
|
||||
}
|
||||
|
||||
if (_filename != null)
|
||||
@@ -472,7 +472,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
|
||||
if (_ignorePaths != null && _ignorePaths.length > 0)
|
||||
{
|
||||
_ignorePathMap = new PathMap();
|
||||
_ignorePathMap = new PathMap<String>();
|
||||
for (int i = 0; i < _ignorePaths.length; i++)
|
||||
_ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]);
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.PortMapper;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
@@ -130,13 +131,17 @@ public class JettyStart implements ClientApp {
|
||||
Server server = (Server) lc;
|
||||
Connector[] connectors = server.getConnectors();
|
||||
if (connectors.length > 0) {
|
||||
int port = connectors[0].getPort();
|
||||
if (port > 0) {
|
||||
_port = port;
|
||||
String host = connectors[0].getHost();
|
||||
if (host.equals("0.0.0.0") || host.equals("::"))
|
||||
host = "127.0.0.1";
|
||||
_context.portMapper().register(PortMapper.SVC_EEPSITE, host, port);
|
||||
Connector conn = connectors[0];
|
||||
if (conn instanceof NetworkConnector) {
|
||||
NetworkConnector nconn = (NetworkConnector) conn;
|
||||
int port = nconn.getPort();
|
||||
if (port > 0) {
|
||||
_port = port;
|
||||
String host = nconn.getHost();
|
||||
if (host.equals("0.0.0.0") || host.equals("::"))
|
||||
host = "127.0.0.1";
|
||||
_context.portMapper().register(PortMapper.SVC_EEPSITE, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@ import org.mortbay.util.LineInput;
|
||||
* </pre>
|
||||
*
|
||||
* 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 $
|
||||
* @author Greg Wilkins
|
||||
@@ -59,14 +60,14 @@ public class MultiPartRequest
|
||||
//private static Log log = LogFactory.getLog(MultiPartRequest.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
HttpServletRequest _request;
|
||||
LineInput _in;
|
||||
String _boundary;
|
||||
String _encoding;
|
||||
byte[] _byteBoundary;
|
||||
MultiMap<String> _partMap = new MultiMap<String>(10);
|
||||
int _char=-2;
|
||||
boolean _lastPart=false;
|
||||
private final HttpServletRequest _request;
|
||||
private final LineInput _in;
|
||||
private final String _boundary;
|
||||
private final String _encoding;
|
||||
private final byte[] _byteBoundary;
|
||||
private final MultiMap<String> _partMap = new MultiMap<String>(10);
|
||||
private int _char=-2;
|
||||
private boolean _lastPart=false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** 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.
@@ -112,6 +112,20 @@ public interface I2PSocket extends Closeable {
|
||||
* @since 0.8.9
|
||||
*/
|
||||
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:
|
||||
|
@@ -38,6 +38,10 @@ public interface I2PSocketManager {
|
||||
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
|
||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||
* and different signing keys
|
||||
|
@@ -70,11 +70,15 @@
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-webapp.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
||||
<pathelement location="../../systray/java/build/systray.jar" />
|
||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||
<pathelement location="../../../installer/lib/wrapper/all/wrapper.jar" />
|
||||
<pathelement location="../../jrobin/java/build/jrobin.jar" />
|
||||
|
||||
<!-- following jars only present for debian builds -->
|
||||
<pathelement location="../../jetty/jettylib/tomcat-api.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
@@ -362,17 +366,22 @@
|
||||
** -trimSpaces Trim spaces in template text between actions, directives
|
||||
-->
|
||||
<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>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.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" />
|
||||
<!-- tomcat-api.jar only present for debian builds -->
|
||||
<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/tomcat-util.jar" />
|
||||
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
|
||||
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
|
||||
<pathelement location="../../systray/java/build/obj" />
|
||||
@@ -403,10 +412,13 @@
|
||||
<classpath>
|
||||
<pathelement location="../../jetty/jettylib/jasper-runtime.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" />
|
||||
<!-- tomcat-api.jar only present for debian builds -->
|
||||
<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-el.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>");
|
||||
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");
|
||||
if (maxVersion != null &&
|
||||
VersionComparator.comp(maxVersion, oldVersion) < 0) {
|
||||
@@ -480,7 +487,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
||||
}
|
||||
// we don't need the original file anymore.
|
||||
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;
|
||||
}
|
||||
if (PluginStarter.isPluginRunning(appName, _context)) {
|
||||
@@ -498,7 +505,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
||||
} else {
|
||||
if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
|
||||
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;
|
||||
}
|
||||
if (!destDir.mkdir()) {
|
||||
@@ -518,7 +525,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
||||
to.delete();
|
||||
// install != update. Changing the user's settings like this is probabbly a bad idea.
|
||||
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) {
|
||||
Properties pluginProps = PluginStarter.pluginProperties();
|
||||
pluginProps.setProperty(PluginStarter.PREFIX + appName + PluginStarter.ENABLED, "false");
|
||||
@@ -534,19 +541,19 @@ class PluginUpdateRunner extends UpdateRunner {
|
||||
String linkURL = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
|
||||
String link;
|
||||
if (linkName != null && linkURL != null)
|
||||
link = "<a target=\"_blank\" href=\"" + linkURL + "\"/>" + linkName + "</a>";
|
||||
link = "<a target=\"_blank\" href=\"" + linkURL + "\"/>" + linkName + ' ' + version + "</a>";
|
||||
else
|
||||
link = appName;
|
||||
link = appName + ' ' + version;
|
||||
statusDone("<b>" + _t("Plugin {0} installed and started", link) + "</b>");
|
||||
}
|
||||
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) {
|
||||
statusDone("<b>" + _t("Plugin {0} installed but failed to start", appName) + ": " + e + "</b>");
|
||||
_log.error("Error starting plugin " + appName, e);
|
||||
statusDone("<b>" + _t("Plugin {0} installed but failed to start", appName + ' ' + version) + ": " + e + "</b>");
|
||||
_log.error("Error starting plugin " + appName + ' ' + version, e);
|
||||
}
|
||||
} 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
|
||||
protected void service(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
|
||||
protected void doGet(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
|
||||
byte[] data;
|
||||
String name = srq.getParameter("plugin");
|
||||
data = NavHelper.getBinary(name);
|
||||
|
@@ -573,7 +573,18 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
private void startPlugin(String app) {
|
||||
try {
|
||||
PluginStarter.startPlugin(_context, app);
|
||||
addFormNotice(_t("Started plugin {0}", 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));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
addFormError(_t("Error starting plugin {0}", 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, 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) {
|
||||
_context = ctx;
|
||||
}
|
||||
@@ -297,8 +313,8 @@ public class PluginStarter implements Runnable {
|
||||
|
||||
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");
|
||||
if (minVersion != null &&
|
||||
@@ -306,6 +322,7 @@ public class PluginStarter implements Runnable {
|
||||
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
||||
log.error(foo);
|
||||
disablePlugin(appName);
|
||||
foo = gettext("This plugin requires I2P version {0} or higher", minVersion, ctx);
|
||||
throw new Exception(foo);
|
||||
}
|
||||
|
||||
@@ -315,6 +332,7 @@ public class PluginStarter implements Runnable {
|
||||
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
||||
log.error(foo);
|
||||
disablePlugin(appName);
|
||||
foo = gettext("This plugin requires Java version {0} or higher", minVersion, ctx);
|
||||
throw new Exception(foo);
|
||||
}
|
||||
|
||||
@@ -325,6 +343,18 @@ public class PluginStarter implements Runnable {
|
||||
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
||||
log.error(foo);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -334,6 +364,7 @@ public class PluginStarter implements Runnable {
|
||||
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
||||
log.error(foo);
|
||||
disablePlugin(appName);
|
||||
foo = gettext("Plugin requires Jetty version {0} or lower", maxVersion, ctx);
|
||||
throw new Exception(foo);
|
||||
}
|
||||
|
||||
@@ -1002,6 +1033,14 @@ public class PluginStarter implements Runnable {
|
||||
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 */
|
||||
private static String ngettext(String s, String p, int n, I2PAppContext ctx) {
|
||||
return Messages.getString(n, s, p, ctx);
|
||||
|
@@ -17,9 +17,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
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.authentication.DigestAuthenticator;
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
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.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
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.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
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.ServletHolder;
|
||||
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.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
import org.tanukisoftware.wrapper.WrapperManager;
|
||||
@@ -96,7 +99,7 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
private final ClientAppManager _mgr;
|
||||
private volatile ClientAppState _state = UNINITIALIZED;
|
||||
private static Server _server;
|
||||
private static Timer _jettyTimer;
|
||||
private static ScheduledExecutorScheduler _jettyTimer;
|
||||
private String _listenPort;
|
||||
private String _listenHost;
|
||||
private String _sslListenPort;
|
||||
@@ -231,6 +234,7 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
changeState(STOPPING);
|
||||
if (PluginStarter.pluginsEnabled(_context))
|
||||
(new I2PAppThread(new PluginStopper(_context), "PluginStopper")).start();
|
||||
stopAllWebApps();
|
||||
try {
|
||||
_server.stop();
|
||||
} catch (Exception ie) {}
|
||||
@@ -239,7 +243,9 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
portMapper.unregister(PortMapper.SVC_HTTPS_CONSOLE);
|
||||
synchronized(RouterConsoleRunner.class) {
|
||||
if (_jettyTimer != null) {
|
||||
_jettyTimer.cancel();
|
||||
try {
|
||||
_jettyTimer.stop();
|
||||
} catch (Exception e) {}
|
||||
_jettyTimer = null;
|
||||
}
|
||||
}
|
||||
@@ -363,6 +369,22 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
* DefaultHandler
|
||||
* RequestLogHandler (opt)
|
||||
*</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() {
|
||||
File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
|
||||
@@ -375,8 +397,9 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
|
||||
// so Jetty can find WebAppConfiguration
|
||||
System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
|
||||
_server = new Server();
|
||||
_server.setGracefulShutdown(1000);
|
||||
// FIXME
|
||||
// http://dev.eclipse.org/mhonarc/lists/jetty-users/msg03487.html
|
||||
//_server.setGracefulShutdown(1000);
|
||||
|
||||
// In Jetty 6, QTP was not concurrent, so we switched to
|
||||
// ThreadPoolExecutor with a fixed-size queue, a set maxThreads,
|
||||
@@ -408,14 +431,11 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
// class not found...
|
||||
//System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
|
||||
LinkedBlockingQueue<Runnable> lbq = new LinkedBlockingQueue<Runnable>(4*MAX_THREADS);
|
||||
QueuedThreadPool qtp = new QueuedThreadPool(lbq);
|
||||
// min and max threads will be set below
|
||||
//qtp.setMinThreads(MIN_THREADS);
|
||||
//qtp.setMaxThreads(MAX_THREADS);
|
||||
qtp.setMaxIdleTimeMs(MAX_IDLE_TIME);
|
||||
// min and max threads will be reset below
|
||||
QueuedThreadPool qtp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, MAX_IDLE_TIME, lbq);
|
||||
qtp.setName(THREAD_NAME);
|
||||
qtp.setDaemon(true);
|
||||
_server.setThreadPool(qtp);
|
||||
_server = new Server(qtp);
|
||||
//}
|
||||
|
||||
HandlerCollection hColl = new HandlerCollection();
|
||||
@@ -502,27 +522,15 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
} finally {
|
||||
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
//if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
|
||||
// _server.addListener('[' + host + "]:" + _listenPort);
|
||||
//else
|
||||
// _server.addListener(host + ':' + _listenPort);
|
||||
AbstractConnector lsnr;
|
||||
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();
|
||||
}
|
||||
HttpConfiguration httpConfig = new HttpConfiguration();
|
||||
// number of acceptors, (default) number of selectors
|
||||
ServerConnector lsnr = new ServerConnector(_server, 1, 0,
|
||||
new HttpConnectionFactory(httpConfig));
|
||||
//lsnr.setUseDirectBuffers(false); // default true seems to be leaky
|
||||
lsnr.setHost(host);
|
||||
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.setAcceptors(1); // default changed to 2 somewhere in Jetty 7?
|
||||
//_server.addConnector(lsnr);
|
||||
connectors.add(lsnr);
|
||||
boundAddresses++;
|
||||
@@ -586,22 +594,19 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
} finally {
|
||||
if (testSock != null) try { testSock.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
// TODO if class not found use SslChannelConnector
|
||||
AbstractConnector ssll;
|
||||
if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
|
||||
SslSelectChannelConnector sssll = new SslSelectChannelConnector(sslFactory);
|
||||
sssll.setUseDirectBuffers(false); // default true seems to be leaky
|
||||
ssll = sssll;
|
||||
} else {
|
||||
// Jetty 6 and NIO on Java 5 don't get along that well
|
||||
SslSocketConnector sssll = new SslSocketConnector(sslFactory);
|
||||
ssll = sssll;
|
||||
}
|
||||
HttpConfiguration httpConfig = new HttpConfiguration();
|
||||
httpConfig.setSecureScheme("https");
|
||||
httpConfig.setSecurePort(sslPort);
|
||||
httpConfig.addCustomizer(new SecureRequestCustomizer());
|
||||
// number of acceptors, (default) number of selectors
|
||||
ServerConnector ssll = new ServerConnector(_server, 1, 0,
|
||||
new SslConnectionFactory(sslFactory, "http/1.1"),
|
||||
new HttpConnectionFactory(httpConfig));
|
||||
//sssll.setUseDirectBuffers(false); // default true seems to be leaky
|
||||
ssll.setHost(host);
|
||||
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.setAcceptors(1); // default changed to 2 somewhere in Jetty 7?
|
||||
//_server.addConnector(ssll);
|
||||
connectors.add(ssll);
|
||||
boundAddresses++;
|
||||
@@ -638,17 +643,25 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||
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();
|
||||
rootWebApp = new LocaleWebAppHandler(_context,
|
||||
"/", _webAppsDir + ROUTERCONSOLE + ".war",
|
||||
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);
|
||||
|
||||
} catch (Exception ioe) {
|
||||
@@ -709,7 +722,13 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
for (int i = 0; i < fileNames.length; i++) {
|
||||
String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
||||
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 {
|
||||
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
||||
WebAppStarter.startWebApp(_context, chColl, appName, path);
|
||||
@@ -945,7 +964,12 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
// see HashSessionManager javadoc
|
||||
synchronized(RouterConsoleRunner.class) {
|
||||
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);
|
||||
}
|
||||
@@ -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 {
|
||||
private static final WarFilenameFilter _filter = new WarFilenameFilter();
|
||||
public static WarFilenameFilter instance() { return _filter; }
|
||||
|
@@ -15,6 +15,7 @@ import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
import org.apache.tomcat.SimpleInstanceManager;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
@@ -97,7 +98,11 @@ public class WebAppConfiguration implements Configuration {
|
||||
// Ticket #957... don't know why...
|
||||
// Only really required if started manually, but we don't know that from here
|
||||
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");
|
||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
|
||||
@@ -173,11 +178,13 @@ public class WebAppConfiguration implements Configuration {
|
||||
}
|
||||
} else {
|
||||
// Java 9 - assume everything in lib/ is in the classpath
|
||||
// except addressbook.jar
|
||||
File libDir = new File(ctx.getBaseDir(), "lib");
|
||||
File[] files = libDir.listFiles();
|
||||
if (files != null) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -191,6 +198,10 @@ public class WebAppConfiguration implements Configuration {
|
||||
/** @since Jetty 7 */
|
||||
public void configure(WebAppContext context) throws Exception {
|
||||
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 */
|
||||
|
@@ -109,17 +109,30 @@ public class WebAppStarter {
|
||||
|
||||
// this does the passwords...
|
||||
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
|
||||
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];
|
||||
for (int j = 0; j < classNames.length; j++)
|
||||
newClassNames[j] = classNames[j];
|
||||
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
||||
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) {}
|
||||
str = request.getParameter("end");
|
||||
if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
||||
boolean hideLegend = Boolean.parseBoolean((String) request.getParameter("hideLegend"));
|
||||
boolean hideGrid = Boolean.parseBoolean((String) request.getParameter("hideGrid"));
|
||||
boolean hideTitle = Boolean.parseBoolean((String) request.getParameter("hideTitle"));
|
||||
boolean showEvents = Boolean.parseBoolean((String) request.getParameter("showEvents"));
|
||||
boolean hideLegend = Boolean.parseBoolean(request.getParameter("hideLegend"));
|
||||
boolean hideGrid = Boolean.parseBoolean(request.getParameter("hideGrid"));
|
||||
boolean hideTitle = Boolean.parseBoolean(request.getParameter("hideTitle"));
|
||||
boolean showEvents = Boolean.parseBoolean(request.getParameter("showEvents"));
|
||||
boolean showCredit = false;
|
||||
if (request.getParameter("showCredit") != null)
|
||||
showCredit = Boolean.parseBoolean((String) request.getParameter("showCredit"));
|
||||
showCredit = Boolean.parseBoolean(request.getParameter("showCredit"));
|
||||
if (fakeBw)
|
||||
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
|
||||
else
|
||||
|
@@ -389,7 +389,7 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
|
||||
boolean ok = ssess.queueSocket(i2ps);
|
||||
if (!ok) {
|
||||
_log.logAlways(Log.WARN, "Accept queue overflow for " + ssess);
|
||||
try { i2ps.close(); } catch (IOException ioe) {}
|
||||
try { i2ps.reset(); } catch (IOException ioe) {}
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
|
@@ -564,7 +564,7 @@ class SAMStreamSession implements SAMMessageSess {
|
||||
int id = createSocketHandler(i2ps, 0);
|
||||
if (id == 0) {
|
||||
_log.error("SAM STREAM session handler not created!");
|
||||
i2ps.close();
|
||||
i2ps.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -383,7 +383,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
||||
Log log = ctx.logManager().getLog(SAMv3StreamSession.class);
|
||||
log.error("SSL error", gse);
|
||||
try {
|
||||
i2ps.close();
|
||||
i2ps.reset();
|
||||
} catch (IOException ee) {}
|
||||
throw new RuntimeException("SSL error", gse);
|
||||
}
|
||||
@@ -401,7 +401,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn("Error forwarding", ioe);
|
||||
try {
|
||||
i2ps.close();
|
||||
i2ps.reset();
|
||||
} catch (IOException ee) {}
|
||||
continue;
|
||||
}
|
||||
@@ -433,7 +433,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
|
||||
clientServerSock.close();
|
||||
} catch (IOException ee) {}
|
||||
try {
|
||||
i2ps.close();
|
||||
i2ps.reset();
|
||||
} catch (IOException ee) {}
|
||||
continue ;
|
||||
}
|
||||
|
@@ -67,6 +67,32 @@ class I2PSocketFull implements I2PSocket {
|
||||
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; }
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||
* and different signing keys
|
||||
|
@@ -30,7 +30,9 @@ class MessageOutputStream extends OutputStream {
|
||||
private final AtomicBoolean _closed = new AtomicBoolean();
|
||||
private long _written;
|
||||
private int _writeTimeout;
|
||||
private ByteCache _dataCache;
|
||||
private final ByteCache _dataCache;
|
||||
private final int _originalBufferSize;
|
||||
private int _currentBufferSize;
|
||||
private final Flusher _flusher;
|
||||
private volatile long _lastBuffered;
|
||||
/** 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) {
|
||||
super();
|
||||
_dataCache = ByteCache.getInstance(128, bufSize);
|
||||
_originalBufferSize = bufSize;
|
||||
_currentBufferSize = bufSize;
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(MessageOutputStream.class);
|
||||
_buf = _dataCache.acquire().getData(); // new byte[bufSize];
|
||||
@@ -75,7 +79,7 @@ class MessageOutputStream extends OutputStream {
|
||||
_dataLock = new Object();
|
||||
_writeTimeout = -1;
|
||||
_passiveFlushDelay = passiveFlushDelay;
|
||||
_nextBufferSize = -1;
|
||||
_nextBufferSize = 0;
|
||||
//_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 });
|
||||
_flusher = new Flusher(timer);
|
||||
@@ -92,7 +96,16 @@ class MessageOutputStream extends OutputStream {
|
||||
|
||||
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
|
||||
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
|
||||
// code that reads from it is synchronized
|
||||
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 (_valid + remaining < _buf.length) {
|
||||
if (_valid + remaining < maxBuffer) {
|
||||
// simply buffer the data, no flush
|
||||
System.arraycopy(b, cur, _buf, _valid, remaining);
|
||||
_valid += remaining;
|
||||
@@ -131,19 +147,17 @@ class MessageOutputStream extends OutputStream {
|
||||
// buffer whatever we can fit then flush,
|
||||
// repeating until we've pushed all of the
|
||||
// data through
|
||||
int toWrite = _buf.length - _valid;
|
||||
int toWrite = maxBuffer - _valid;
|
||||
System.arraycopy(b, cur, _buf, _valid, toWrite);
|
||||
remaining -= toWrite;
|
||||
cur += toWrite;
|
||||
_valid = _buf.length;
|
||||
_valid = maxBuffer;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("write() direct valid = " + _valid);
|
||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||
_written += _valid;
|
||||
_valid = 0;
|
||||
throwAnyError();
|
||||
|
||||
locked_updateBufferSize();
|
||||
}
|
||||
}
|
||||
if (ws != null) {
|
||||
@@ -207,17 +221,21 @@ class MessageOutputStream extends OutputStream {
|
||||
/**
|
||||
* 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;
|
||||
if (size > 0) {
|
||||
// update the buffer size to the requested amount
|
||||
_dataCache.release(new ByteArray(_buf));
|
||||
_dataCache = ByteCache.getInstance(128, size);
|
||||
ByteArray ba = _dataCache.acquire();
|
||||
_buf = ba.getData();
|
||||
_nextBufferSize = -1;
|
||||
// No, never do this, to avoid ByteCache churn.
|
||||
//_dataCache.release(new ByteArray(_buf));
|
||||
//_dataCache = ByteCache.getInstance(128, size);
|
||||
//ByteArray ba = _dataCache.acquire();
|
||||
//_buf = ba.getData();
|
||||
_currentBufferSize = size;
|
||||
_nextBufferSize = 0;
|
||||
}
|
||||
return _currentBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,7 +291,6 @@ class MessageOutputStream extends OutputStream {
|
||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||
_written += _valid;
|
||||
_valid = 0;
|
||||
locked_updateBufferSize();
|
||||
_dataLock.notifyAll();
|
||||
sent = true;
|
||||
}
|
||||
@@ -336,7 +353,6 @@ class MessageOutputStream extends OutputStream {
|
||||
ws = _dataReceiver.writeData(_buf, 0, _valid);
|
||||
_written += _valid;
|
||||
_valid = 0;
|
||||
locked_updateBufferSize();
|
||||
_dataLock.notifyAll();
|
||||
}
|
||||
}
|
||||
@@ -409,7 +425,6 @@ class MessageOutputStream extends OutputStream {
|
||||
ba = new ByteArray(_buf);
|
||||
_buf = null;
|
||||
_valid = 0;
|
||||
locked_updateBufferSize();
|
||||
}
|
||||
_dataLock.notifyAll();
|
||||
}
|
||||
@@ -494,7 +509,6 @@ class MessageOutputStream extends OutputStream {
|
||||
ws = target.writeData(_buf, 0, _valid);
|
||||
_written += _valid;
|
||||
_valid = 0;
|
||||
locked_updateBufferSize();
|
||||
_dataLock.notifyAll();
|
||||
}
|
||||
long afterBuild = System.currentTimeMillis();
|
||||
|
@@ -13,6 +13,22 @@
|
||||
</filter-mapping>
|
||||
|
||||
<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 -->
|
||||
|
||||
<!-- non-.jsp URLs -->
|
||||
|
@@ -16,20 +16,22 @@
|
||||
-->
|
||||
<pathelement location="${lib}/commons-el.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" />
|
||||
<!-- tomcat-api.jar only present for debian builds -->
|
||||
<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-scan.jar" />
|
||||
<pathelement location="${lib}/jasper-el.jar" />
|
||||
|
||||
<pathelement location="lib/jstl.jar" />
|
||||
<pathelement location="lib/standard.jar" />
|
||||
<pathelement location="${lib}/jasper-runtime.jar" />
|
||||
<pathelement location="${lib}/commons-logging.jar" />
|
||||
<!-- jasper-el.jar only present for debian builds -->
|
||||
<pathelement location="${lib}/jasper-el.jar" />
|
||||
<pathelement location="${lib}/jetty-util.jar" />
|
||||
<pathelement location="${ant.home}/lib/ant.jar" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
<pathelement location="../../addressbook/dist/addressbook.jar" />
|
||||
</path>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
|
@@ -314,6 +314,9 @@ public class AddressbookBean extends BaseBean
|
||||
}
|
||||
if (action.equals(_t("Delete Entry")))
|
||||
search = null;
|
||||
} else if (action.equals(_t("Add Alternate"))) {
|
||||
// button won't be in UI
|
||||
message = "Unsupported";
|
||||
}
|
||||
if( changed ) {
|
||||
try {
|
||||
|
@@ -231,7 +231,7 @@ public class NamingServiceBean extends AddressbookBean
|
||||
if (_context.getBooleanProperty(PROP_PW_ENABLE) ||
|
||||
(serial != null && serial.equals(lastSerial))) {
|
||||
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) {
|
||||
try {
|
||||
// throws IAE with translated message
|
||||
@@ -243,20 +243,38 @@ public class NamingServiceBean extends AddressbookBean
|
||||
Destination oldDest = getNamingService().lookup(host, nsOptions, outProperties);
|
||||
if (oldDest != null && destination.equals(oldDest.toBase64())) {
|
||||
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);
|
||||
} else {
|
||||
try {
|
||||
Destination dest = new Destination(destination);
|
||||
if (oldDest != null) {
|
||||
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"));
|
||||
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) {
|
||||
changed = true;
|
||||
if (oldDest == null)
|
||||
if (oldDest == null || action.equals(_t("Add Alternate")))
|
||||
message = _t("Destination added for {0}.", displayHost);
|
||||
else
|
||||
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"))) {
|
||||
String name = null;
|
||||
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) {
|
||||
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 displayHost = uni.equals(n) ? n : uni + " (" + n + ')';
|
||||
if (!success) {
|
||||
|
@@ -19,11 +19,10 @@
|
||||
* 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.PrintWriter;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -31,25 +30,29 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
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.
|
||||
*
|
||||
* This was a GenericServlet, we make it an HttpServlet solely to provide a hook
|
||||
* for SusiDNS to wake us up when the subscription list changes.
|
||||
* This was a GenericServlet, we make it an HttpServlet solely to provide a
|
||||
* simple page to display status.
|
||||
*
|
||||
* @since 0.9.30 moved from addressbook to SusiDNS
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class Servlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private transient DaemonThread thread;
|
||||
private transient Thread thread;
|
||||
//private String nonce;
|
||||
//private static final String PROP_NONCE = "addressbook.nonce";
|
||||
|
||||
/**
|
||||
* Hack to allow susidns to kick the daemon when the subscription list changes.
|
||||
* URL must be /addressbook/ with wakeup param set, and nonce param set from system property.
|
||||
* Simple output to verify that the addressbook servlet is running.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
@@ -70,6 +73,7 @@ public class Servlet extends HttpServlet {
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(ServletConfig config) {
|
||||
try {
|
||||
@@ -82,17 +86,39 @@ public class Servlet extends HttpServlet {
|
||||
//System.setProperty(PROP_NONCE, this.nonce);
|
||||
String[] args = new String[1];
|
||||
args[0] = config.getInitParameter("home");
|
||||
this.thread = new DaemonThread(args);
|
||||
this.thread.setDaemon(true);
|
||||
this.thread.setName("Addressbook");
|
||||
this.thread.start();
|
||||
//System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||
//System.out.println("INFO: config root under " + args[0]);
|
||||
try {
|
||||
ClassLoader cl = getServletContext().getClassLoader();
|
||||
Class cls = Class.forName("net.i2p.addressbook.DaemonThread", true, cl);
|
||||
// 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: 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
|
||||
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();
|
||||
}
|
||||
}
|
@@ -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