forked from I2P_Developers/i2p.i2p
Compare commits
43 Commits
gitlab-ci
...
build-debi
| Author | SHA1 | Date | |
|---|---|---|---|
| c0a0aa7700 | |||
| 4a9131c39d | |||
| b47269f14e | |||
| fb317b44ba | |||
| e64e12b3fb | |||
| f71e59a049 | |||
| 169fb59d7d | |||
|
|
922178b2c7 | ||
|
|
74a9193ba5 | ||
|
|
335409f1d2 | ||
|
|
d6edb9e96c | ||
| f150855f1c | |||
|
|
655ce09796 | ||
|
|
91ebec15d5 | ||
|
|
b17d321503 | ||
|
|
a6398d88a9 | ||
|
|
59969db16c | ||
|
|
b68a5ea7fd | ||
|
|
c2234685b9 | ||
|
|
ce7daaa02a | ||
|
|
b19999f95a | ||
|
|
92ecc9f8e8 | ||
|
|
aa2ba92db8 | ||
|
|
5f3c41244b | ||
|
|
bf29132898 | ||
|
|
a424331b78 | ||
|
|
ccb0c279f7 | ||
|
|
7fe01fb9a7 | ||
|
|
66c4c10a78 | ||
|
|
163967311e | ||
|
|
75734448c5 | ||
|
|
aed1de84b8 | ||
|
|
51560a8ec8 | ||
|
|
ec89a80e80 | ||
|
|
41c7b7382a | ||
|
|
b4e1fbd857 | ||
|
|
517ff4fa24 | ||
|
|
106b1a696d | ||
|
|
6cab545c45 | ||
|
|
619923dbf8 | ||
|
|
ed0ecdf253 | ||
|
|
d42ef2223d | ||
|
|
e461004ed9 |
31
.dockerignore
Normal file
31
.dockerignore
Normal file
@@ -0,0 +1,31 @@
|
||||
.idea
|
||||
.git
|
||||
Dockerfile
|
||||
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
build
|
||||
apps/BOB/build
|
||||
apps/addressbook/build
|
||||
apps/desktopgui/build
|
||||
apps/i2pcontrol/build
|
||||
apps/i2psnark/build
|
||||
apps/i2ptunnel/build
|
||||
apps/imagegen/build
|
||||
apps/jetty/build
|
||||
apps/jrobin/build
|
||||
apps/ministreaming/java/build
|
||||
apps/ministreaming/build
|
||||
apps/routerconsole/build
|
||||
apps/sam/build
|
||||
apps/streaming/build
|
||||
apps/susidns/build
|
||||
apps/susimail/build
|
||||
apps/systray/build
|
||||
core/java/build
|
||||
core/build
|
||||
installer/build
|
||||
router/java/build
|
||||
router/build
|
||||
|
||||
@@ -22,3 +22,45 @@ test:
|
||||
only:
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
# Make sure we can build a docker image
|
||||
# It's cached for later jobs
|
||||
build_docker:
|
||||
stage: test
|
||||
image: docker:19.03.12
|
||||
services:
|
||||
- docker:19.03.12-dind
|
||||
script:
|
||||
# Try to load latest branch image from local tar or from registry
|
||||
- docker load -i ci-exports/$CI_COMMIT_REF_SLUG.tar || docker pull $CI_REGISTRY_IMAGE:latest || true
|
||||
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:latest .
|
||||
- mkdir -p ci-exports/
|
||||
- docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
variables:
|
||||
# When using dind service, we need to instruct docker to talk with
|
||||
# the daemon started inside of the service. The daemon is available
|
||||
# with a network connection instead of the default
|
||||
# /var/run/docker.sock socket. Docker 19.03 does this automatically
|
||||
# by setting the DOCKER_HOST in
|
||||
# https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29
|
||||
#
|
||||
# The 'docker' hostname is the alias of the service container as described at
|
||||
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services.
|
||||
#
|
||||
# Specify to Docker where to create the certificates, Docker will
|
||||
# create them automatically on boot, and will create
|
||||
# `/certs/client` that will be shared between the service and job
|
||||
# container, thanks to volume mount from config.toml
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
cache:
|
||||
# The same key should be used across branches
|
||||
key: "$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- ci-exports/*.tar
|
||||
only:
|
||||
- master
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export JAVA_HOME=/opt/jdk/jre
|
||||
|
||||
# Ensure user rights
|
||||
chown -R i2p:nobody /opt/i2p
|
||||
chmod -R u+rwx /opt/i2p
|
||||
|
||||
gosu i2p /opt/i2p/i2psvc /opt/i2p/wrapper.config wrapper.pidfile=/var/tmp/i2p.pid \
|
||||
wrapper.name=i2p \
|
||||
wrapper.displayname="I2P Service" \
|
||||
wrapper.statusfile=/var/tmp/i2p.status \
|
||||
wrapper.java.statusfile=/var/tmp/i2p.java.status \
|
||||
wrapper.logfile=/var/tmp/wrapper.log
|
||||
80
Dockerfile
80
Dockerfile
@@ -1,62 +1,40 @@
|
||||
FROM meeh/java8server:latest
|
||||
# Docker image based on Alpine with Java.
|
||||
# Use a multi-stage build to reduce the size of the resulting image
|
||||
# We need alpine >v3 in order to install an apache-ant > 1.9
|
||||
FROM debian:buster-slim as builder
|
||||
|
||||
# We use Oracle Java to run I2P, but uses the openjdk to build it.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Build installer
|
||||
RUN apt-get update \
|
||||
# Workaround for installing openjdk-11-jre-headless
|
||||
&& mkdir -p /usr/share/man/man1 \
|
||||
&& apt-get -qqqy install debhelper ant debconf gettext libgmp-dev po-debconf fakeroot \
|
||||
build-essential quilt dh-apparmor dh-systemd libservice-wrapper-java libjson-simple-java \
|
||||
devscripts libjetty9-java libtomcat9-java libtaglibs-standard-jstlel-java libgetopt-java \
|
||||
bash-completion
|
||||
|
||||
MAINTAINER Mikal Villa <mikal@sigterm.no>
|
||||
WORKDIR /tmp/build
|
||||
COPY . ./
|
||||
|
||||
ENV GIT_BRANCH="master"
|
||||
ENV I2P_PREFIX="/opt/i2p"
|
||||
ENV PATH=${I2P_PREFIX}/bin:$PATH
|
||||
ENV JAVA_HOME=/usr/lib/jvm/default-jvm
|
||||
RUN ant debian
|
||||
|
||||
ENV GOSU_VERSION=1.7
|
||||
ENV GOSU_SHASUM="34049cfc713e8b74b90d6de49690fa601dc040021980812b2f1f691534be8a50 /usr/local/bin/gosu"
|
||||
|
||||
RUN mkdir /user && adduser -S -h /user i2p && chown -R i2p:nobody /user
|
||||
|
||||
# Adding files first, since Docker.expt is required for installation
|
||||
ADD Docker.expt /tmp/Docker.expt
|
||||
ADD Docker.entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Required for wget https
|
||||
RUN apk add --no-cache openssl
|
||||
# Gosu is a replacement for su/sudo in docker and not a backdoor :) See https://github.com/tianon/gosu
|
||||
RUN wget -O /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64 \
|
||||
&& echo "${GOSU_SHASUM}" | sha256sum -c && chmod +x /usr/local/bin/gosu
|
||||
|
||||
#
|
||||
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
|
||||
# image under 200mb we need to remove all the build dependencies in the same "RUN" / layer.
|
||||
#
|
||||
|
||||
# The main layer
|
||||
RUN apk --no-cache add build-base git gettext tar bzip2 apache-ant openjdk8 expect \
|
||||
&& mkdir -p /usr/src/build \
|
||||
&& cd /usr/src/build \
|
||||
&& git clone -b ${GIT_BRANCH} https://github.com/i2p/i2p.i2p.git \
|
||||
&& cd /usr/src/build/i2p.i2p \
|
||||
&& echo "noExe=true" >> build.properties \
|
||||
&& ant installer-linux \
|
||||
&& cp i2pinstall*.jar /tmp/i2pinstall.jar \
|
||||
&& mkdir -p /opt \
|
||||
&& chown i2p:root /opt \
|
||||
&& chmod u+rw /opt \
|
||||
&& gosu i2p expect -f /tmp/Docker.expt \
|
||||
&& cd ${I2P_PREFIX} \
|
||||
&& rm -fr man docs *.bat *.command *.app /tmp/i2pinstall.jar /tmp/Docker.expt \
|
||||
&& rm -fr /usr/src/build \
|
||||
&& apk --purge del build-base apache-ant expect tcl expat git openjdk8 openjdk8-jre openjdk8-jre-base openjdk8-jre-lib bzip2 tar \
|
||||
binutils-libs binutils pkgconfig libcurl libc-dev musl-dev g++ make fortify-headers pkgconf giflib libssh2 libxdmcp libxcb \
|
||||
libx11 pcre alsa-lib libxi libxrender libxml2 readline bash openssl \
|
||||
&& rm -fr /usr/lib/jvm/default-jre \
|
||||
&& ln -sf /opt/jdk/jre /usr/lib/jvm/default-jre \
|
||||
&& chmod a+x /entrypoint.sh
|
||||
# Second stage only using the installer from the last stage
|
||||
# ---------------------------------------------------------
|
||||
# We can't use alpine here as the java service wrapper is built with glibc
|
||||
# alpine uses musl
|
||||
FROM openjdk:11.0-jre-slim
|
||||
|
||||
# "install" i2p by copying over installed files
|
||||
COPY --from=builder /tmp/*.deb /tmp/
|
||||
|
||||
# Install and configure
|
||||
RUN apt-get update -qqq \
|
||||
&& apt-get -qqqy install geoip-database famfamfam-flag-png \
|
||||
&& dpkb -i /tmp/*
|
||||
|
||||
EXPOSE 7654 7656 7657 7658 4444 6668 8998 7659 7660 4445 15000-20000
|
||||
|
||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||
USER i2psvc
|
||||
ENTRYPOINT [ "/usr/bin/i2prouter" ]
|
||||
CMD start
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class Daemon {
|
||||
* client applications.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* the user's I2P Site so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
@@ -111,7 +111,7 @@ class Daemon {
|
||||
* The NamingService to update, generally the root NamingService from the context.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* the user's I2P Site so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
|
||||
22
apps/i2pcontrol/build.gradle
Normal file
22
apps/i2pcontrol/build.gradle
Normal file
@@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
id 'war'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'java'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
providedCompile project(':router')
|
||||
providedCompile project(':apps:jetty')
|
||||
providedCompile files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
}
|
||||
|
||||
war {
|
||||
archiveName 'jsonrpc.war'
|
||||
webXml = file('web.xml')
|
||||
}
|
||||
@@ -55,7 +55,7 @@ import java.util.StringTokenizer;
|
||||
* This handles the starting and stopping of Jetty
|
||||
* from a single static class so it can be called via clients.config.
|
||||
*
|
||||
* This makes installation of a new eepsite a turnkey operation.
|
||||
* This makes installation of a new I2P Site a turnkey operation.
|
||||
*
|
||||
* Usage: I2PControlController -d $PLUGIN [start|stop]
|
||||
*
|
||||
|
||||
@@ -13,7 +13,7 @@ sourceSets {
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':apps:systray')
|
||||
providedCompile project(':apps:systray')
|
||||
compile 'gnu.getopt:java-getopt:1.0.13'
|
||||
providedCompile project(':apps:ministreaming')
|
||||
providedCompile project(':apps:jetty')
|
||||
@@ -60,5 +60,4 @@ war {
|
||||
from 'mime.properties'
|
||||
}
|
||||
webXml = file('web.xml')
|
||||
// TODO why is this in there? WEB-INF/lib/systray.jar
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -57,7 +59,6 @@ public class I2PSnarkUtil {
|
||||
private int _i2cpPort;
|
||||
private final Map<String, String> _opts;
|
||||
private volatile I2PSocketManager _manager;
|
||||
private boolean _configured;
|
||||
private volatile boolean _connecting;
|
||||
private final Set<Hash> _banlist;
|
||||
private int _maxUploaders;
|
||||
@@ -84,6 +85,10 @@ public class I2PSnarkUtil {
|
||||
public static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
|
||||
public static final boolean DEFAULT_USE_DHT = true;
|
||||
public static final String EEPGET_USER_AGENT = "I2PSnark";
|
||||
private static final List<String> HIDDEN_I2CP_OPTS = Arrays.asList(new String[] {
|
||||
PROP_MAX_BW, "inbound.length", "outbound.length", "inbound.quantity", "outbound.quantity"
|
||||
});
|
||||
|
||||
|
||||
public I2PSnarkUtil(I2PAppContext ctx) {
|
||||
this(ctx, "i2psnark");
|
||||
@@ -142,25 +147,34 @@ public class I2PSnarkUtil {
|
||||
/** @since 0.9.1 */
|
||||
public I2PAppContext getContext() { return _context; }
|
||||
|
||||
public boolean configured() { return _configured; }
|
||||
|
||||
/**
|
||||
* @param i2cpHost may be null for no change
|
||||
* @param i2cpPort may be 0 for no change
|
||||
* @param opts may be null for no change
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
|
||||
if (i2cpHost != null)
|
||||
_i2cpHost = i2cpHost;
|
||||
if (i2cpPort > 0)
|
||||
_i2cpPort = i2cpPort;
|
||||
// can't remove any options this way...
|
||||
if (opts != null)
|
||||
_opts.putAll(opts);
|
||||
if (opts != null) {
|
||||
synchronized(_opts) {
|
||||
// removed options...
|
||||
for (Iterator<String> iter = _opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String k = iter.next();
|
||||
if (!HIDDEN_I2CP_OPTS.contains(k) && !opts.containsKey(k))
|
||||
iter.remove();
|
||||
}
|
||||
_opts.putAll(opts);
|
||||
}
|
||||
}
|
||||
// this updates the session options and tells the router
|
||||
setMaxUpBW(_maxUpBW);
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setMaxUploaders(int limit) {
|
||||
_maxUploaders = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,13 +183,16 @@ public class I2PSnarkUtil {
|
||||
*/
|
||||
public void setMaxUpBW(int limit) {
|
||||
_maxUpBW = limit;
|
||||
_opts.put(PROP_MAX_BW, Integer.toString(limit * (1024 * 6 / 5))); // add a little for overhead
|
||||
_configured = true;
|
||||
synchronized(_opts) {
|
||||
_opts.put(PROP_MAX_BW, Integer.toString(limit * (1024 * 6 / 5))); // add a little for overhead
|
||||
}
|
||||
if (_manager != null) {
|
||||
I2PSession sess = _manager.getSession();
|
||||
if (sess != null) {
|
||||
Properties newProps = new Properties();
|
||||
newProps.putAll(_opts);
|
||||
synchronized(_opts) {
|
||||
newProps.putAll(_opts);
|
||||
}
|
||||
sess.updateOptions(newProps);
|
||||
}
|
||||
}
|
||||
@@ -183,17 +200,24 @@ public class I2PSnarkUtil {
|
||||
|
||||
public void setMaxConnections(int limit) {
|
||||
_maxConnections = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setStartupDelay(int minutes) {
|
||||
_startupDelay = minutes;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public String getI2CPHost() { return _i2cpHost; }
|
||||
public int getI2CPPort() { return _i2cpPort; }
|
||||
public Map<String, String> getI2CPOptions() { return _opts; }
|
||||
|
||||
/**
|
||||
* @return a copy
|
||||
*/
|
||||
public Map<String, String> getI2CPOptions() {
|
||||
synchronized(_opts) {
|
||||
return new HashMap<String, String>(_opts);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEepProxyHost() { return _proxyHost; }
|
||||
public int getEepProxyPort() { return _proxyPort; }
|
||||
public boolean getEepProxySet() { return _shouldProxy; }
|
||||
@@ -225,9 +249,8 @@ public class I2PSnarkUtil {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connecting to I2P", new Exception("I did it"));
|
||||
Properties opts = _context.getProperties();
|
||||
if (_opts != null) {
|
||||
for (Map.Entry<String, String> entry : _opts.entrySet() )
|
||||
opts.setProperty(entry.getKey(), entry.getValue());
|
||||
synchronized(_opts) {
|
||||
opts.putAll(_opts);
|
||||
}
|
||||
// override preference and start with two tunnels. IdleChecker will ramp up/down as necessary
|
||||
String sin = opts.getProperty("inbound.quantity");
|
||||
|
||||
@@ -1068,7 +1068,8 @@ class PeerCoordinator implements PeerListener
|
||||
// just in case
|
||||
removePartialPiece(piece);
|
||||
// Oops. We didn't actually download this then... :(
|
||||
downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
|
||||
// Reports of counter going negative?
|
||||
//downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
|
||||
// Mark this peer as not having the piece. PeerState will update its bitfield.
|
||||
for (Piece pc : wantedPieces) {
|
||||
if (pc.getId() == piece) {
|
||||
|
||||
@@ -461,7 +461,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
*/
|
||||
private boolean writeTorrents(PrintWriter out, HttpServletRequest req, boolean canWrite) throws IOException {
|
||||
/** dl, ul, down rate, up rate, peers, size */
|
||||
final long stats[] = {0,0,0,0,0,0};
|
||||
final long stats[] = new long[6];
|
||||
String peerParam = req.getParameter("p");
|
||||
String stParam = req.getParameter("st");
|
||||
|
||||
@@ -2479,8 +2479,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (!_context.isRouterContext()) {
|
||||
try {
|
||||
// class only in standalone builds
|
||||
Class helper = Class.forName("org.klomp.snark.standalone.ConfigUIHelper");
|
||||
Method getLangSettings = helper.getMethod("getLangSettings", new Class[] {I2PAppContext.class});
|
||||
Class<?> helper = Class.forName("org.klomp.snark.standalone.ConfigUIHelper");
|
||||
Method getLangSettings = helper.getMethod("getLangSettings", I2PAppContext.class);
|
||||
String langSettings = (String) getLangSettings.invoke(null, _context);
|
||||
// If we get to here, we have the language settings
|
||||
out.write("<tr><td>");
|
||||
|
||||
@@ -19,7 +19,7 @@ sourceSets {
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':apps:ministreaming')
|
||||
providedCompile project(':apps:ministreaming')
|
||||
compile 'gnu.getopt:java-getopt:1.0.13'
|
||||
providedCompile project(':apps:jetty')
|
||||
}
|
||||
@@ -106,6 +106,5 @@ war {
|
||||
exclude '*.jsi'
|
||||
exclude '*.jsp'
|
||||
webXml = file('jsp/web.xml')
|
||||
// FIXME why is this in there? WEB-INF/lib/mstreaming.jar
|
||||
}
|
||||
|
||||
|
||||
@@ -291,10 +291,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_socketManagerState = SocketManagerState.INIT;
|
||||
// We could be here a LONG time, holding the lock
|
||||
socketManager = buildSocketManager(tunnel, pkf);
|
||||
/*
|
||||
since we enabled ratchet by default, we're not compatible with ancient servers anyway.
|
||||
// FIXME may not be the right place for this
|
||||
I2PSession sub = addSubsession(tunnel);
|
||||
if (sub != null && _log.shouldLog(Log.WARN))
|
||||
_log.warn("Added subsession " + sub);
|
||||
*/
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Not building a new socket manager since the old one is open [s=" + s + "]");
|
||||
|
||||
@@ -68,7 +68,7 @@ import net.i2p.util.PortMapper;
|
||||
* Rewrite as http://i2p/$b64key/...
|
||||
*
|
||||
* If the $site resolves with the I2P naming service, then it is directed towards
|
||||
* that eepsite, otherwise it is directed towards this client's outproxy (typically
|
||||
* that I2P Site, otherwise it is directed towards this client's outproxy (typically
|
||||
* "squid.i2p"). Only HTTP and HTTPS are supported (no ftp, mailto, etc). Both GET
|
||||
* and POST have been tested, though other $methods should work.
|
||||
*
|
||||
@@ -678,7 +678,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
// allow i2paddresshelper=<b32>.b32.i2p syntax.
|
||||
/*
|
||||
also i2paddresshelper=name.i2p for aliases
|
||||
i.e. on your eepsite put
|
||||
i.e. on your I2P Site put
|
||||
<a href="?i2paddresshelper=name.i2p">This is the name I want to be called.</a>
|
||||
*/
|
||||
Destination _dest = _context.namingService().lookup(ahelperKey);
|
||||
@@ -1351,7 +1351,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
}
|
||||
|
||||
// Redirect to non-addresshelper URL to not clog the browser address bar
|
||||
// and not pass the parameter to the eepsite.
|
||||
// and not pass the parameter to the I2P Site.
|
||||
// This also prevents the not-found error page from looking bad
|
||||
// Syndie can't handle a redirect of a POST
|
||||
if (ahelperPresent && !"POST".equals(method) && !"PUT".equals(method)) {
|
||||
|
||||
@@ -955,6 +955,7 @@ input.tunnelName, input.tunnelDescriptionText, #userAgents, .freetext.tunnelDesc
|
||||
|
||||
#customOptions {
|
||||
margin-top: 15px !important;
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
#tunnelDepth, #tunnelVariance, #tunnelQuantity, #tunnelBackupQuantity,
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
<%=intl._t("Try this if none of the tunnel types below fit your requirements, or you don't know what type of tunnel you need.")%>
|
||||
</td></tr>
|
||||
<tr><td>HTTP/HTTPS</td><td>
|
||||
<%=intl._t("Tunnel that acts as an HTTP proxy for reaching eepsites inside I2P.")%>
|
||||
<%=intl._t("Tunnel that acts as an HTTP proxy for reaching I2P Sites inside I2P.")%>
|
||||
<%=intl._t("Set your browser to use this tunnel as an http proxy, or set your \"http_proxy\" environment variable for command-line applications in GNU/Linux.")%>
|
||||
<%=intl._t("Websites outside I2P can also be reached if an HTTP proxy within I2P is known.")%>
|
||||
</td></tr>
|
||||
@@ -161,7 +161,7 @@
|
||||
</td></tr>
|
||||
<tr><td>HTTP</td><td>
|
||||
<%=intl._t("A server tunnel that is customised for HTTP connections.")%>
|
||||
<%=intl._t("Use this tunnel type if you want to host an eepsite.")%>
|
||||
<%=intl._t("Use this tunnel type if you want to host an I2P Site.")%>
|
||||
</td></tr>
|
||||
<tr><td>IRC</td><td>
|
||||
<%=intl._t("A customised server tunnel for hosting IRC networks inside I2P.")%>
|
||||
|
||||
25
apps/imagegen/build.gradle
Normal file
25
apps/imagegen/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
id 'war'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'identicon/core/src/main/java'
|
||||
srcDir 'imagegen/webapp/src/main/java'
|
||||
srcDir 'zxing/core/src/main/java'
|
||||
srcDir 'zxing/javase/src/main/java'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
providedCompile project(':apps:jetty')
|
||||
}
|
||||
|
||||
war {
|
||||
from 'imagegen/webapp/src/main/webapp/imagegen.css'
|
||||
from 'imagegen/webapp/src/main/webapp/index.html'
|
||||
webXml = file('imagegen/webapp/src/main/webapp/WEB-INF/web.xml')
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package net.i2p.jetty;
|
||||
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -127,7 +129,7 @@ public class I2PLogger implements Logger
|
||||
if (th != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(msg, th);
|
||||
else
|
||||
else if (!(th instanceof ClosedChannelException))
|
||||
_log.logAlways(Log.WARN, msg + ": " + th);
|
||||
} else {
|
||||
_log.logAlways(Log.WARN, msg);
|
||||
|
||||
@@ -317,7 +317,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
buf.append(request.getMethod());
|
||||
buf.append(' ');
|
||||
|
||||
u8buf.append(request.getHttpURI().toString());
|
||||
u8buf.append(request.getRequestURI());
|
||||
|
||||
buf.append(' ');
|
||||
buf.append(request.getProtocol());
|
||||
|
||||
@@ -40,6 +40,7 @@ fi
|
||||
ROUTERFILES="\
|
||||
../../../router/java/src/net/i2p/router/Blocklist.java \
|
||||
../../../router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java \
|
||||
../../../router/java/src/net/i2p/router/sybil/Analysis.java \
|
||||
../../../router/java/src/net/i2p/router/tasks/CoalesceStatsEvent.java \
|
||||
../../../router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java \
|
||||
../../../router/java/src/net/i2p/router/transport/GetBidsJob.java \
|
||||
|
||||
@@ -1009,7 +1009,7 @@ public class PluginStarter implements Runnable {
|
||||
return false;
|
||||
boolean rv = group.activeCount() > 0;
|
||||
|
||||
// Plugins start before the eepsite, and will create the static Timer thread
|
||||
// Plugins start before the I2P Site, and will create the static Timer thread
|
||||
// in RolloverFileOutputStream, which never stops. Don't count it.
|
||||
// Ditto HSQLDB Timer (jwebcache)
|
||||
if (rv) {
|
||||
|
||||
@@ -35,7 +35,6 @@ import net.i2p.jetty.I2PLogger;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.app.RouterApp;
|
||||
import net.i2p.router.news.NewsManager;
|
||||
import net.i2p.router.sybil.Analysis;
|
||||
import net.i2p.router.update.ConsoleUpdateManager;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.FileSuffixFilter;
|
||||
@@ -901,14 +900,6 @@ public class RouterConsoleRunner implements RouterApp {
|
||||
if (_mgr == null)
|
||||
_context.addShutdownTask(new ServerShutdown());
|
||||
ConfigServiceHandler.registerSignalHandler(_context);
|
||||
|
||||
if (_mgr != null &&
|
||||
//_context.getBooleanProperty(HelperBase.PROP_ADVANCED) &&
|
||||
!SystemVersion.isSlow() &&
|
||||
_context.getProperty(Analysis.PROP_FREQUENCY, Analysis.DEFAULT_FREQUENCY) > 0) {
|
||||
// registers and starts itself
|
||||
Analysis.getInstance(_context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
@@ -22,6 +23,7 @@ import net.i2p.router.RouterContext;
|
||||
import static net.i2p.router.web.GraphConstants.*;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.FileSuffixFilter;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SystemVersion;
|
||||
@@ -43,7 +45,7 @@ public class StatSummarizer implements Runnable, ClientApp {
|
||||
private final Log _log;
|
||||
/** list of SummaryListener instances */
|
||||
private final List<SummaryListener> _listeners;
|
||||
private static final int MAX_CONCURRENT_PNG = SystemVersion.isARM() ? 2 : 3;
|
||||
private static final int MAX_CONCURRENT_PNG = SystemVersion.isSlow() ? 1 : 3;
|
||||
private final Semaphore _sem;
|
||||
private volatile boolean _isRunning;
|
||||
private volatile Thread _thread;
|
||||
@@ -91,6 +93,24 @@ public class StatSummarizer implements Runnable, ClientApp {
|
||||
String spec = _context.getProperty("stat.summaries", DEFAULT_DATABASES);
|
||||
String[] rates = DataHelper.split(spec, ",");
|
||||
syncThreads = Math.min(rates.length / 2, 4);
|
||||
// delete files for unconfigured rates
|
||||
Set<String> configured = new HashSet<String>(rates.length);
|
||||
for (String r : rates) {
|
||||
configured.add(SummaryListener.createName(_context, r));
|
||||
}
|
||||
File rrdDir = new File(_context.getRouterDir(), SummaryListener.RRD_DIR);
|
||||
FileFilter filter = new FileSuffixFilter(SummaryListener.RRD_PREFIX, SummaryListener.RRD_SUFFIX);
|
||||
File[] files = rrdDir.listFiles(filter);
|
||||
if (files != null) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File f = files[i];
|
||||
String name = f.getName();
|
||||
String hash = name.substring(SummaryListener.RRD_PREFIX.length(), name.length() - SummaryListener.RRD_SUFFIX.length());
|
||||
if (!configured.contains(hash)) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
syncThreads = 0;
|
||||
deleteOldRRDs();
|
||||
|
||||
@@ -35,8 +35,8 @@ public class SummaryListener implements RateSummaryListener {
|
||||
public static final String PROP_PERSISTENT = "routerconsole.graphPersistent";
|
||||
/** note that .jrb files are NOT compatible with .rrd files */
|
||||
static final String RRD_DIR = "rrd";
|
||||
private static final String RRD_PREFIX = "rrd-";
|
||||
private static final String RRD_SUFFIX = ".jrb";
|
||||
static final String RRD_PREFIX = "rrd-";
|
||||
static final String RRD_SUFFIX = ".jrb";
|
||||
static final ConsolFun CF = ConsolFun.AVERAGE;
|
||||
static final DsType DS = DsType.GAUGE;
|
||||
private static final double XFF = 0.9d;
|
||||
|
||||
@@ -65,7 +65,7 @@ public class CertHelper extends HelperBase {
|
||||
if (!hasTunnels)
|
||||
output(_t("SAM"), null);
|
||||
|
||||
// Eepsite
|
||||
// I2P Site
|
||||
tunnelDir = new File(dir, EEPSITE_DIR);
|
||||
hasTunnels = false;
|
||||
tunnels = tunnelDir.listFiles(new FileSuffixFilter(".crt"));
|
||||
|
||||
@@ -9,6 +9,8 @@ import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppState;
|
||||
@@ -37,6 +39,15 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
public static final String PROP_ENABLE_CLIENT_CHANGE = "routerconsole.enableClientChange";
|
||||
public static final String PROP_ENABLE_PLUGIN_INSTALL = "routerconsole.enablePluginInstall";
|
||||
|
||||
/**
|
||||
* simple regex from
|
||||
* https://stackoverflow.com/questions/8204680/java-regex-email
|
||||
* not the massive RFC 822 compliant one
|
||||
* modified so .i2p will work
|
||||
*/
|
||||
private static final Pattern VALID_EMAIL_ADDRESS_REGEX =
|
||||
Pattern.compile("[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z2]{2,6}", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public ConfigClientsHelper() {}
|
||||
|
||||
/** @since 0.9.14.1 */
|
||||
@@ -302,10 +313,13 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
}
|
||||
s = stripHTML(appProps, "author");
|
||||
if (s != null) {
|
||||
String[] authors = DataHelper.split(s, "[,; \r\n\t]");
|
||||
Matcher m = VALID_EMAIL_ADDRESS_REGEX.matcher(s);
|
||||
String author = m.find() ? m.group() : null;
|
||||
desc.append("<tr><td><b>")
|
||||
.append(_t("Author")).append("</b></td><td>");
|
||||
if (s.indexOf('@') > 0)
|
||||
desc.append("<a href=\"mailto:").append(s).append("\">").append(s).append("</a>");
|
||||
if (author != null)
|
||||
desc.append("<a href=\"mailto:").append(author).append("\">").append(s).append("</a>");
|
||||
else
|
||||
desc.append(s);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class HomeHelper extends HelperBase {
|
||||
//_x("Dev Builds") + S + _x("Development builds of I2P") + S + "http://bobthebuilder.i2p/" + S + I + "script_gear.png" + S +
|
||||
_x("Dev Forum") + S + _x("Development forum") + S + "http://zzz.i2p/" + S + I + "group_gear.png" + S +
|
||||
//_x("diftracker") + S + _x("Bittorrent tracker") + S + "http://diftracker.i2p/" + S + I + "i2psnark.png" + S +
|
||||
"echelon.i2p" + S + _x("I2P Applications") + S + "http://echelon.i2p/" + S + I + "echelon.png" + S +
|
||||
//"echelon.i2p" + S + _x("I2P Applications") + S + "http://echelon.i2p/" + S + I + "echelon.png" + S +
|
||||
//"exchanged.i2p" + S + _x("Anonymous cryptocurrency exchange") + S + "http://exchanged.i2p/" + S + I + "exchanged.png" + S +
|
||||
_x("I2P FAQ") + S + _x("Frequently Asked Questions") + S + "http://i2p-projekt.i2p/faq" + S + I + "question.png" + S +
|
||||
_x("I2P Forum") + S + _x("Community forum") + S + "http://i2pforum.i2p/" + S + I + "group.png" + S +
|
||||
@@ -83,7 +83,7 @@ public class HomeHelper extends HelperBase {
|
||||
//_x("Key Server") + S + _x("OpenPGP Keyserver") + S + "http://keys.i2p/" + S + I + "education.png" + S +
|
||||
//"killyourtv.i2p" + S + _x("Debian and Tahoe-LAFS repositories") + S + "http://killyourtv.i2p/" + S + I + "television_delete.png" + S +
|
||||
_x("MuWire") + S + _x("Easy anonymous file sharing") + S + "http://muwire.i2p/" + S + I + "muwire.png" + S +
|
||||
//_x("Open4You") + S + _x("Free eepsite hosting with PHP and MySQL") + S + "http://open4you.i2p/" + S + I + "open4you-logo.png" + S +
|
||||
//_x("Open4You") + S + _x("Free I2P Site hosting with PHP and MySQL") + S + "http://open4you.i2p/" + S + I + "open4you-logo.png" + S +
|
||||
//_x("Pastebin") + S + _x("Encrypted I2P Pastebin") + S + "http://zerobin.i2p/" + S + I + "paste_plain.png" + S +
|
||||
_x("Planet I2P") + S + _x("I2P News") + S + "http://planet.i2p/" + S + I + "world.png" + S +
|
||||
//_x("I2P Plugins") + S + _x("Add-on directory") + S + "http://i2pwiki.i2p/index.php?title=Plugins" + S + I + "info/plugin_link.png" + S +
|
||||
@@ -307,7 +307,7 @@ public class HomeHelper extends HelperBase {
|
||||
for (App app : apps) {
|
||||
String url;
|
||||
if (app.name.equals(website) && app.url.equals("http://127.0.0.1:7658/")) {
|
||||
// fixup eepsite link
|
||||
// fixup I2P Site link
|
||||
url = SummaryBarRenderer.getEepsiteURL(pm);
|
||||
if (url == null)
|
||||
continue;
|
||||
|
||||
@@ -22,8 +22,8 @@ class Dummy {
|
||||
_t("Web console");
|
||||
_t("SAM application bridge");
|
||||
_t("Application tunnels");
|
||||
_t("My eepsite web server");
|
||||
_t("I2P webserver (eepsite)");
|
||||
_t("My I2P Site web server");
|
||||
_t("I2P webserver (I2P Site)");
|
||||
_t("Browser launch at startup");
|
||||
_t("BOB application bridge");
|
||||
_t("I2P Router Console");
|
||||
@@ -35,7 +35,7 @@ class Dummy {
|
||||
// keep the old string here as well for existing installs
|
||||
_t("shared clients");
|
||||
_t("IRC proxy");
|
||||
_t("eepsite");
|
||||
_t("I2P Site");
|
||||
_t("I2P webserver");
|
||||
_t("HTTP Proxy");
|
||||
// hardcoded in i2psnark
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%> <a href="peers#upnp">[<%=intl._t("UPnP Status")%>]</a></th>
|
||||
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%> <a href="peers?tx=upnp">[<%=intl._t("UPnP Status")%>]</a></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 668 B |
@@ -73,6 +73,14 @@ img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
img:not(img[src$="i2plogo.png"]){
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -o-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
}
|
||||
|
||||
a:hover img {
|
||||
filter: drop-shadow(0 0 1px #f60);
|
||||
}
|
||||
@@ -105,14 +113,11 @@ pre {
|
||||
padding: 8px;
|
||||
margin-bottom: 2px;
|
||||
text-align: center !important;
|
||||
border: 1px solid #dee2e6;
|
||||
color: #33333f;
|
||||
font-size: 8pt;
|
||||
clear: left;/* fixes a bug in Opera */
|
||||
border-radius: 2px;
|
||||
background: #fafaff;
|
||||
box-shadow: inset 0 0 0 1px #dee2e6;
|
||||
filter: drop-shadow(0 0 1px #999daf);
|
||||
}
|
||||
|
||||
.routersummary div[style="height: 36px;"] {
|
||||
@@ -4150,12 +4155,13 @@ button.download.control:hover, button.download.control:focus {
|
||||
text-indent: 0;
|
||||
text-align: left;
|
||||
min-width: 0 !important;
|
||||
padding: 5px 7px 5px 22px !important;
|
||||
padding: 5px 7px 1px 22px !important;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.routersummary .cancel {
|
||||
text-transform: capitalize;
|
||||
padding: 5px 7px 1px 22px !important;
|
||||
}
|
||||
|
||||
.routersummary .reload[value="restartImmediate"] {
|
||||
|
||||
@@ -133,11 +133,18 @@
|
||||
<td><%=intl._t("Added Date")%></td>
|
||||
<td><%=addr.getAdded()%></td>
|
||||
</tr>
|
||||
<%
|
||||
String lastmod = addr.getModded();
|
||||
if (lastmod.length() > 0) {
|
||||
%>
|
||||
<tr class="list${book.trClass}">
|
||||
<td><%=intl._t("Last Modified")%></td>
|
||||
<td><%=addr.getModded()%></td>
|
||||
<td><%=lastmod%></td>
|
||||
</tr>
|
||||
<% } // showNotes %>
|
||||
<%
|
||||
} // lastmod
|
||||
} // showNotes
|
||||
%>
|
||||
<tr class="list${book.trClass}">
|
||||
<td><%=intl._t("Destination")%></td>
|
||||
<td class="destinations"><div class="destaddress" tabindex="0"><%=addr.getDestination()%></div></td>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<p>
|
||||
<%=intl._t("The addressbook application regularly polls your subscriptions and merges their content into your \"router\" address book.")%>
|
||||
<%=intl._t("Then it merges your \"local\" address book into the router address book as well.")%>
|
||||
<%=intl._t("If configured, the router address book is now written to the \"published\" address book, which will be publicly available if you are running an eepsite.")%>
|
||||
<%=intl._t("If configured, the router address book is now written to the \"published\" address book, which will be publicly available if you are running an I2P Site.")%>
|
||||
</p><p>
|
||||
<%=intl._t("The router also uses a private address book, which is not merged or published.")%>
|
||||
<%=intl._t("Hosts in the private address book can be accessed by you but their addresses are never distributed to others.")%>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="help" id="helpsubs">
|
||||
<p class="help">
|
||||
<%=intl._t("The subscription file contains a list of i2p URLs.")%>
|
||||
<%=intl._t("The addressbook application regularly checks this list for new eepsites.")%>
|
||||
<%=intl._t("The addressbook application regularly checks this list for new I2P Sites.")%>
|
||||
<%=intl._t("Those URLs refer to published hosts.txt files.")%>
|
||||
<%=intl._t("The default subscription is the hosts.txt from {0}, which is updated infrequently.", "i2p-projekt.i2p")%>
|
||||
<%=intl._t("So it is a good idea to add additional subscriptions to sites that have the latest addresses.")%>
|
||||
|
||||
@@ -124,4 +124,4 @@ task codeCoverageReport(type: JacocoReport) {
|
||||
}
|
||||
}
|
||||
|
||||
//apply from: file('gradle/update.gradle')
|
||||
apply from: file('gradle/update.gradle')
|
||||
|
||||
@@ -9,15 +9,16 @@
|
||||
|
||||
# Javadocs
|
||||
# Note: Include the trailing slash! Don't surround the URL in quotes!
|
||||
javasedocs.url=http://docs.oracle.com/javase/7/docs/api/
|
||||
javaeedocs.url=http://docs.oracle.com/javaee/7/api/
|
||||
javasedocs.url=https://docs.oracle.com/javase/8/docs/api/
|
||||
javaeedocs.url=https://docs.oracle.com/javaee/7/api/
|
||||
# The following link is for 9.4.x
|
||||
#jettydocs.url=http://download.eclipse.org/jetty/stable-9/apidocs/
|
||||
jettydocs.url=http://download.eclipse.org/jetty/9.2.21.v20170120/apidocs/
|
||||
wrapperdocs.url=http://wrapper.tanukisoftware.com/jdoc/
|
||||
# last one available on archive.eclipse.org
|
||||
jettydocs.url=https://archive.eclipse.org/jetty/9.3.9.v20160517/apidocs/
|
||||
wrapperdocs.url=https://wrapper.tanukisoftware.com/jdoc/
|
||||
# these are only for unit test javadocs
|
||||
i2pdocs.url=http://docs.i2p-projekt.de/javadoc/
|
||||
junitdocs.url=http://junit.org/apidocs/
|
||||
junitdocs.url=https://junit.org/junit5/docs/current/api/
|
||||
# This will go in the jar manifests
|
||||
build.built-by=unknown
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
-->
|
||||
<property file="override.properties"/>
|
||||
<property file="build.properties"/>
|
||||
<!-- When changing, also change javadoc URL in build.properties, and checksum in apps/jetty/build.xml -->
|
||||
<!-- When changing, also change javadoc URL in build.properties,
|
||||
and checksum in apps/jetty/build.xml
|
||||
and versions in apps/jetty/build.gradle
|
||||
-->
|
||||
<property name="jetty.ver" value="9.3.29.v20201019" />
|
||||
<property name="tomcat.ver" value="9.0.40" />
|
||||
|
||||
@@ -970,7 +973,7 @@
|
||||
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:org.apache.http.conn.ssl:org.apache.http.conn.util:org.apache.http.util:org.json.simple:com.southernstorm.noise.crypto.x25519:com.southernstorm.noise.crypto.chacha20:org.minidns:org.minidns.*" />
|
||||
<group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
|
||||
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters:com.maxmind.*:com.southernstorm.noise.*" />
|
||||
<group title="Router Console" packages="net.i2p.router.web:net.i2p.router.web.*:net.i2p.router.update:net.i2p.router.sybil:edu.internet2.ndt:net.i2p.router.news:com.vuze.*" />
|
||||
<group title="Router Console" packages="net.i2p.router.web:net.i2p.router.web.*:net.i2p.router.update:edu.internet2.ndt:net.i2p.router.news:com.vuze.*" />
|
||||
<!-- apps and bridges starting here, alphabetical please -->
|
||||
<group title="Addressbook Application" packages="net.i2p.addressbook:net.i2p.router.naming:net.metanotion:net.metanotion.*" />
|
||||
<group title="BOB Bridge" packages="net.i2p.BOB" />
|
||||
|
||||
69
core/java/test/junit/net/i2p/util/ConvertToHashTest.java
Normal file
69
core/java/test/junit/net/i2p/util/ConvertToHashTest.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ConvertToHashTest {
|
||||
private static final String zzzDotI2pBase32Hash = "lhbd7ojcaiofbfku7ixh47qj537g572zmhdc4oilvugzxdpdghua";
|
||||
private static final String zzzDotI2pBase64Hash = "WcI~uSICHFCVVPoufn4J7v5u~1lhxi45C60Nm43jMeg=";
|
||||
private static final String zzzDotI2pBase64Dest = "GKapJ8koUcBj~jmQzHsTYxDg2tpfWj0xjQTzd8BhfC9c3OS5fwPBNajgF-eOD6eCjFTqTlorlh7Hnd8kXj1qblUGXT-tDoR9~YV8dmXl51cJn9MVTRrEqRWSJVXbUUz9t5Po6Xa247Vr0sJn27R4KoKP8QVj1GuH6dB3b6wTPbOamC3dkO18vkQkfZWUdRMDXk0d8AdjB0E0864nOT~J9Fpnd2pQE5uoFT6P0DqtQR2jsFvf9ME61aqLvKPPWpkgdn4z6Zkm-NJOcDz2Nv8Si7hli94E9SghMYRsdjU-knObKvxiagn84FIwcOpepxuG~kFXdD5NfsH0v6Uri3usE3XWD7Pw6P8qVYF39jUIq4OiNMwPnNYzy2N4mDMQdsdHO3LUVh~DEppOy9AAmEoHDjjJxt2BFBbGxfdpZCpENkwvmZeYUyNCCzASqTOOlNzdpne8cuesn3NDXIpNnqEE6Oe5Qm5YOJykrX~Vx~cFFT3QzDGkIjjxlFBsjUJyYkFjBQAEAAcAAA==";
|
||||
|
||||
|
||||
@Test
|
||||
public void getHashNullPeer() {
|
||||
assertNull(ConvertToHash.getHash(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashB64() {
|
||||
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Hash);
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashB64DotI2P() {
|
||||
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Hash + ".i2p");
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashDestinationB64() {
|
||||
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Dest);
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashDestinationB64DotI2P() {
|
||||
Hash hash = ConvertToHash.getHash(zzzDotI2pBase64Dest + ".i2p");
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase64(), zzzDotI2pBase64Hash);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashB32() {
|
||||
Hash hash = ConvertToHash.getHash(zzzDotI2pBase32Hash);
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase32(), zzzDotI2pBase32Hash + ".b32.i2p");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHashB32DotI2P() {
|
||||
String zzzB32I2P = zzzDotI2pBase32Hash + ".b32.i2p";
|
||||
Hash hash = ConvertToHash.getHash(zzzB32I2P);
|
||||
assertNotNull(hash);
|
||||
assertEquals(hash.toBase32(), zzzB32I2P);
|
||||
}
|
||||
|
||||
/**
|
||||
* The case where a destination cannot be resolved at all
|
||||
*/
|
||||
@Test
|
||||
public void getHashResolveDestinationFail() {
|
||||
assertNull(ConvertToHash.getHash("unknown.i2p"));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ task prepUpdateSmall(type: Copy) {
|
||||
dependsOn ':apps:ministreaming:jar', ':apps:streaming:jar'
|
||||
dependsOn ':apps:routerconsole:jar', ':apps:i2ptunnel:i2ptunnelJar'
|
||||
dependsOn ':apps:routerconsole:war', ':apps:i2ptunnel:war'
|
||||
dependsOn ':apps:addressbook:war'
|
||||
dependsOn ':apps:addressbook:jar'
|
||||
// Base dir
|
||||
into 'pkg-temp'
|
||||
into('lib') {
|
||||
@@ -22,18 +22,13 @@ task prepUpdateSmall(type: Copy) {
|
||||
project(':apps:streaming').jar.archivePath,
|
||||
project(':apps:routerconsole').jar.archivePath,
|
||||
project(':apps:i2ptunnel').i2ptunnelJar.archivePath,
|
||||
project(':apps:jrobin').jar.archivePath,
|
||||
]}
|
||||
// pulled out of routerconsole.jar in 0.7.12, someday we can take out of updater
|
||||
// name without version so we can overwrite if we upgrade
|
||||
from('apps/jrobin/jrobin-1.5.9.1.jar') {
|
||||
rename { 'jrobin.jar' }
|
||||
}
|
||||
}
|
||||
into('webapps') {
|
||||
from {[
|
||||
project(':apps:routerconsole').war.archivePath,
|
||||
project(':apps:i2ptunnel').war.archivePath,
|
||||
project(':apps:addressbook').war.archivePath,
|
||||
]}
|
||||
}
|
||||
}
|
||||
@@ -42,9 +37,12 @@ task prepUpdate(type: Copy) {
|
||||
dependsOn prepUpdateSmall
|
||||
dependsOn ':apps:BOB:jar', ':apps:sam:jar'
|
||||
dependsOn ':apps:i2psnark:i2psnarkJar', ':apps:systray:jar'
|
||||
//dependsOn ':apps:desktopgui:jar'
|
||||
dependsOn ':apps:jetty:jar'
|
||||
dependsOn ':apps:desktopgui:jar'
|
||||
dependsOn ':apps:susidns:war', ':apps:susimail:war'
|
||||
dependsOn ':apps:i2psnark:war'
|
||||
dependsOn ':apps:i2pcontrol:war'
|
||||
dependsOn ':apps:imagegen:war'
|
||||
// Base dir
|
||||
into 'pkg-temp'
|
||||
into('lib') {
|
||||
@@ -52,10 +50,9 @@ task prepUpdate(type: Copy) {
|
||||
project(':apps:BOB').jar.archivePath,
|
||||
project(':apps:sam').jar.archivePath,
|
||||
project(':apps:i2psnark').i2psnarkJar.archivePath,
|
||||
// include systray changes in 0.7.5
|
||||
project(':apps:systray').jar.archivePath,
|
||||
// removed from updater in 0.9
|
||||
//project(':apps:desktopgui').jar.archivePath,
|
||||
project(':apps:desktopgui').jar.archivePath,
|
||||
project(':apps:jetty').jar.archivePath,
|
||||
]}
|
||||
// as of 0.7.12; someday, we can remove these from the updater
|
||||
from 'apps/susidns/src/WEB-INF/lib/jstl.jar'
|
||||
@@ -66,6 +63,8 @@ task prepUpdate(type: Copy) {
|
||||
project(':apps:susidns').war.archivePath,
|
||||
project(':apps:susimail').war.archivePath,
|
||||
project(':apps:i2psnark').war.archivePath,
|
||||
project(':apps:i2pcontrol').war.archivePath,
|
||||
project(':apps:imagegen').war.archivePath,
|
||||
]}
|
||||
}
|
||||
from('history.txt') {
|
||||
@@ -75,4 +74,35 @@ task prepUpdate(type: Copy) {
|
||||
String more = '\n\n----------------\n\nEARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE'
|
||||
ant.concat(more, append: 'true', destfile: 'pkg-temp/history.txt')
|
||||
}
|
||||
from 'LICENSE.txt'
|
||||
into('licenses') { from 'licenses' }
|
||||
from 'installer/resources/blocklist.txt'
|
||||
from 'installer/resources/deletelist.txt'
|
||||
into('certificates') { from 'installer/resources/certificates' }
|
||||
into('locale') { from 'installer/resources/locale' }
|
||||
into('man') { from 'installer/resources/man' }
|
||||
}
|
||||
|
||||
task updaterRouter(type: Zip) {
|
||||
description 'makes an i2pupdate.zip file containing core and router jars only'
|
||||
dependsOn prepUpdateRouter
|
||||
archiveName 'i2pupdate.zip'
|
||||
destinationDir file('.')
|
||||
from 'pkg-temp'
|
||||
}
|
||||
|
||||
task updaterSmall(type: Zip) {
|
||||
description 'makes an i2pupdate.zip file with a subset of the resources'
|
||||
dependsOn prepUpdateSmall
|
||||
archiveName 'i2pupdate.zip'
|
||||
destinationDir file('.')
|
||||
from 'pkg-temp'
|
||||
}
|
||||
|
||||
task updater(type: Zip) {
|
||||
description 'makes an i2pupdate.zip file'
|
||||
dependsOn prepUpdate
|
||||
archiveName 'i2pupdate.zip'
|
||||
destinationDir file('.')
|
||||
from 'pkg-temp'
|
||||
}
|
||||
|
||||
42
history.txt
42
history.txt
@@ -1,4 +1,46 @@
|
||||
2021-01-20 zzz
|
||||
* Console: Fix link to UPnP status
|
||||
* SSU: Fix deadlock with router restart
|
||||
|
||||
2021-01-14 zzz
|
||||
* Router:
|
||||
- Change default encryption type to ECIES-X25519 (proposal 156)
|
||||
- Move Sybil subsystem from console to router
|
||||
- Limit max addresses in RI
|
||||
|
||||
2021-01-13 zzz
|
||||
* Jetty: Fix URI in request logs
|
||||
|
||||
2021-01-12 zzz
|
||||
* i2psnark: Don't decrement downloaded counter after receiving bad piece
|
||||
|
||||
2021-01-11 zzz
|
||||
* Console: Delete rrd files for no-longer-configured stats at startup
|
||||
|
||||
2021-01-08 zzz
|
||||
* i2ptunnel: Disable shared clients (DSA) (part 2)
|
||||
* SSU: Fix bandwidth estimator deadlock (ticket #2798)
|
||||
|
||||
2021-01-07 zzz
|
||||
* Router: Disable reseeding and NTP in vmCommSystem
|
||||
* SSU: Implement fast retransmit (ticket #2427)
|
||||
|
||||
2021-01-05 zzz
|
||||
* Console: Reduce limit of concurrent graph generation on slow devices
|
||||
* i2psnark: Add ability to remove I2CP options
|
||||
* SusiDNS: Hide last-modified on details page if empty
|
||||
|
||||
2021-01-04 zzz
|
||||
* Build:
|
||||
- Gradle build fixes
|
||||
- Update external javadoc links
|
||||
|
||||
2021-01-02 zzz
|
||||
* Sybil: Reduce default threshold
|
||||
* Tunnels: Improve error handling at OBEP
|
||||
|
||||
2020-12-31 zzz
|
||||
* Console: Use local time on graphs by default
|
||||
* NetDB:
|
||||
- Drop lookups with replies going to us
|
||||
- Extend lookup expire time
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.i2p.data.i2np;
|
||||
|
||||
/**
|
||||
* Small records.
|
||||
* 236 bytes.
|
||||
* Preliminary, see proposal 157.
|
||||
*
|
||||
* Note that these are layer-encrypted and layer-decrypted in-place.
|
||||
* Do not cache.
|
||||
*
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public class ShortEncryptedBuildRecord extends EncryptedBuildRecord {
|
||||
|
||||
public final static int LENGTH = ShortTunnelBuildMessage.SHORT_RECORD_SIZE;
|
||||
|
||||
/** @throws IllegalArgumentException if data is not correct length (null is ok) */
|
||||
public ShortEncryptedBuildRecord(byte data[]) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return LENGTH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package net.i2p.data.i2np;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
/**
|
||||
* Variable size, small records.
|
||||
* Preliminary, see proposal 157.
|
||||
*
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public class ShortTunnelBuildMessage extends TunnelBuildMessage {
|
||||
public static final int MESSAGE_TYPE = 25;
|
||||
public static final int SHORT_RECORD_SIZE = 236;
|
||||
|
||||
/** zero record count, will be set with readMessage() */
|
||||
public ShortTunnelBuildMessage(I2PAppContext context) {
|
||||
super(context, 0);
|
||||
}
|
||||
|
||||
public ShortTunnelBuildMessage(I2PAppContext context, int records) {
|
||||
super(context, records);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateWrittenLength() { return 1 + super.calculateWrittenLength(); }
|
||||
|
||||
@Override
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
||||
@Override
|
||||
public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException {
|
||||
if (type != MESSAGE_TYPE)
|
||||
throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
int r = data[offset] & 0xff;
|
||||
if (r <= 0 || r > MAX_RECORD_COUNT)
|
||||
throw new I2NPMessageException("Bad record count " + r);
|
||||
RECORD_COUNT = r;
|
||||
if (dataSize != calculateWrittenLength())
|
||||
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
|
||||
_records = new EncryptedBuildRecord[RECORD_COUNT];
|
||||
offset++;
|
||||
for (int i = 0; i < RECORD_COUNT; i++) {
|
||||
byte rec[] = new byte[SHORT_RECORD_SIZE];
|
||||
System.arraycopy(data, offset, rec, 0, SHORT_RECORD_SIZE);
|
||||
setRecord(i, new ShortEncryptedBuildRecord(rec));
|
||||
offset += SHORT_RECORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int writeMessageBody(byte[] out, int curIndex) throws I2NPMessageException {
|
||||
int remaining = out.length - (curIndex + calculateWrittenLength());
|
||||
if (remaining < 0)
|
||||
throw new I2NPMessageException("Not large enough (too short by " + remaining + ")");
|
||||
if (RECORD_COUNT <= 0 || RECORD_COUNT > MAX_RECORD_COUNT)
|
||||
throw new I2NPMessageException("Bad record count " + RECORD_COUNT);
|
||||
out[curIndex++] = (byte) RECORD_COUNT;
|
||||
for (int i = 0; i < RECORD_COUNT; i++) {
|
||||
System.arraycopy(_records[i].getData(), 0, out, curIndex, SHORT_RECORD_SIZE);
|
||||
curIndex += SHORT_RECORD_SIZE;
|
||||
}
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
buf.append("[ShortTunnelBuildMessage: " +
|
||||
"\n\tRecords: ").append(getRecordCount())
|
||||
.append(']');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package net.i2p.data.i2np;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* Transmitted from the new outbound endpoint to the creator through a
|
||||
* reply tunnel.
|
||||
* Variable size, small records.
|
||||
* Preliminary, see proposal 157.
|
||||
*
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public class ShortTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
|
||||
public static final int MESSAGE_TYPE = 26;
|
||||
public static final int SHORT_RECORD_SIZE = ShortTunnelBuildMessage.SHORT_RECORD_SIZE;
|
||||
|
||||
/** zero record count, will be set with readMessage() */
|
||||
public ShortTunnelBuildReplyMessage(I2PAppContext context) {
|
||||
super(context, 0);
|
||||
}
|
||||
|
||||
public ShortTunnelBuildReplyMessage(I2PAppContext context, int records) {
|
||||
super(context, records);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateWrittenLength() { return 1 + super.calculateWrittenLength(); }
|
||||
|
||||
@Override
|
||||
public int getType() { return MESSAGE_TYPE; }
|
||||
|
||||
@Override
|
||||
public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException {
|
||||
if (type != MESSAGE_TYPE)
|
||||
throw new I2NPMessageException("Message type is incorrect for this message");
|
||||
int r = data[offset] & 0xff;
|
||||
if (r <= 0 || r > MAX_RECORD_COUNT)
|
||||
throw new I2NPMessageException("Bad record count " + r);
|
||||
RECORD_COUNT = r;
|
||||
if (dataSize != calculateWrittenLength())
|
||||
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
|
||||
_records = new EncryptedBuildRecord[RECORD_COUNT];
|
||||
offset++;
|
||||
for (int i = 0; i < RECORD_COUNT; i++) {
|
||||
byte rec[] = new byte[SHORT_RECORD_SIZE];
|
||||
System.arraycopy(data, offset, rec, 0, SHORT_RECORD_SIZE);
|
||||
setRecord(i, new ShortEncryptedBuildRecord(rec));
|
||||
offset += SHORT_RECORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int writeMessageBody(byte[] out, int curIndex) throws I2NPMessageException {
|
||||
int remaining = out.length - (curIndex + calculateWrittenLength());
|
||||
if (remaining < 0)
|
||||
throw new I2NPMessageException("Not large enough (too short by " + remaining + ")");
|
||||
if (RECORD_COUNT <= 0 || RECORD_COUNT > MAX_RECORD_COUNT)
|
||||
throw new I2NPMessageException("Bad record count " + RECORD_COUNT);
|
||||
out[curIndex++] = (byte) RECORD_COUNT;
|
||||
for (int i = 0; i < RECORD_COUNT; i++) {
|
||||
System.arraycopy(_records[i].getData(), 0, out, curIndex, SHORT_RECORD_SIZE);
|
||||
curIndex += SHORT_RECORD_SIZE;
|
||||
}
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
buf.append("[ShortTunnelBuildReplyMessage: " +
|
||||
"\n\tRecords: ").append(getRecordCount())
|
||||
.append(']');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ public class RouterInfo extends DatabaseEntry {
|
||||
public static final String PROP_NETWORK_ID = "netId";
|
||||
public static final String PROP_CAPABILITIES = "caps";
|
||||
public static final char CAPABILITY_HIDDEN = 'H';
|
||||
private static final int MAX_ADDRESSES = 16;
|
||||
|
||||
/** Public string of chars which serve as bandwidth capacity markers
|
||||
* NOTE: individual chars defined in Router.java
|
||||
@@ -203,11 +204,14 @@ public class RouterInfo extends DatabaseEntry {
|
||||
*
|
||||
* @param addresses may be null
|
||||
* @throws IllegalStateException if RouterInfo is already signed or addresses previously set
|
||||
* @throws IllegalArgumentException if too many addresses
|
||||
*/
|
||||
public void setAddresses(Collection<RouterAddress> addresses) {
|
||||
if (_signature != null || !_addresses.isEmpty())
|
||||
throw new IllegalStateException();
|
||||
if (addresses != null) {
|
||||
if (addresses.size() > MAX_ADDRESSES)
|
||||
throw new IllegalArgumentException("too many addresses");
|
||||
_addresses.addAll(addresses);
|
||||
}
|
||||
}
|
||||
@@ -575,6 +579,8 @@ public class RouterInfo extends DatabaseEntry {
|
||||
_published = DataHelper.readLong(din, 8);
|
||||
// EOF will be thrown in properties read below
|
||||
int numAddresses = din.read();
|
||||
if (numAddresses > MAX_ADDRESSES)
|
||||
throw new DataFormatException("too many addresses");
|
||||
for (int i = 0; i < numAddresses; i++) {
|
||||
RouterAddress address = new RouterAddress();
|
||||
address.readBytes(din);
|
||||
|
||||
@@ -50,6 +50,7 @@ import net.i2p.router.startup.CreateRouterInfoJob;
|
||||
import net.i2p.router.startup.PortableWorkingDir;
|
||||
import net.i2p.router.startup.StartupJob;
|
||||
import net.i2p.router.startup.WorkingDir;
|
||||
import net.i2p.router.sybil.Analysis;
|
||||
import net.i2p.router.tasks.*;
|
||||
import net.i2p.router.transport.FIFOBandwidthLimiter;
|
||||
import net.i2p.router.transport.UPnPScannerCallback;
|
||||
@@ -928,6 +929,12 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
// but just to be safe
|
||||
_context.simpleTimer2().addEvent(r, 0);
|
||||
_context.commSystem().initGeoIP();
|
||||
|
||||
if (!SystemVersion.isSlow() &&
|
||||
_context.getProperty(Analysis.PROP_FREQUENCY, Analysis.DEFAULT_FREQUENCY) > 0) {
|
||||
// registers and starts itself
|
||||
Analysis.getInstance(_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1928,6 +1935,8 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
}
|
||||
if (downtime > LIVELINESS_DELAY) {
|
||||
System.err.println("WARN: Old router was not shut down gracefully, deleting " + f);
|
||||
if (lastWritten > 0)
|
||||
_eventLog.addEvent(EventLog.CRASHED, (downtime / 60000) + " minutes ago");
|
||||
f.delete();
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 11;
|
||||
public final static long BUILD = 14;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
||||
@@ -864,7 +864,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
if (ts.getAcked())
|
||||
buf.append(" acked");
|
||||
buf.append(" created:</b> ").append(DataHelper.formatTime(ts.getCreated()))
|
||||
.append(" <b>last use:</b> ").append(DataHelper.formatTime(ts.getDate()));
|
||||
.append(" <b>last used:</b> ").append(DataHelper.formatTime(ts.getDate()));
|
||||
buf.append(" <b>expires in:</b> ").append(DataHelper.formatDuration2(expires)).append(" with ");
|
||||
buf.append(size).append(" tags remaining");
|
||||
if (ts.getNextKey() != null)
|
||||
@@ -1178,8 +1178,11 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
_context.clock().now(), newtsID, _myOBKeyID);
|
||||
_tagSet = ts;
|
||||
_currentOBTagSetID = newtsID;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got nextkey " + key + "\nratchet to new OB ES TS:\n" + ts);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got nextkey " + key +
|
||||
"from " + (_destination != null ? _destination.toBase32() : "???") +
|
||||
"\nold OB TS:\n" + oldts +
|
||||
"\nratchet to new OB ES TS:\n" + ts);
|
||||
} else {
|
||||
// this is about my inbound tag set
|
||||
if (key.equals(_hisOBKey)) {
|
||||
@@ -1273,8 +1276,11 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
_context.clock().now(), newtsID, _myIBKeyID,
|
||||
MAX_RCV_WINDOW_ES, MAX_RCV_WINDOW_ES);
|
||||
_nextIBRootKey = ts.getNextRootKey();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got nextkey " + key + "\nratchet to new IB ES TS:\n" + ts);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got nextkey " + key +
|
||||
"from " + (_destination != null ? _destination.toBase32() : "???") +
|
||||
"\nold IB TS ID #" + oldtsID +
|
||||
"\nratchet to new IB ES TS:\n" + ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ class RatchetTagSet implements TagSetHandle {
|
||||
private static final byte[] ZEROLEN = new byte[0];
|
||||
private static final int TAGLEN = RatchetSessionTag.LENGTH;
|
||||
private static final int MAX = 65535;
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean TEST_RATCHET = false;
|
||||
// 4 * max streaming window
|
||||
private static final int LOW = TEST_RATCHET ? (MAX - 512) : (MAX - 4096);
|
||||
@@ -572,10 +573,16 @@ class RatchetTagSet implements TagSetHandle {
|
||||
buf.append("\n ").append(n).append('\t').append(tag.toBase64());
|
||||
if (_sessionKeys != null) {
|
||||
byte[] key = _sessionKeys.get(n);
|
||||
if (key != null)
|
||||
if (key != null) {
|
||||
buf.append('\t').append(Base64.encode(key));
|
||||
else
|
||||
} else {
|
||||
buf.append("\tTBD");
|
||||
// set DEBUG if you want to see them all
|
||||
if (!DEBUG) {
|
||||
buf.append(" (" + (sz - (i +1)) + " more)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ public class FloodfillDatabaseLookupMessageHandler implements HandlerJobBuilder
|
||||
//}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dropping lookup request for " + dlm.getSearchKey() + " (throttled), reply was to: " + dlm.getFrom() + " tunnel: " + dlm.getReplyTunnel());
|
||||
_context.statManager().addRateData("netDb.lookupsDropped", 1, 1);
|
||||
_log.warn("Dropping " + dlm.getSearchType() + " lookup request for " + dlm.getSearchKey() + " (throttled), reply was to: " + dlm.getFrom() + " tunnel: " + dlm.getReplyTunnel());
|
||||
_context.statManager().addRateData("netDb.lookupsDropped", 1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,8 @@ public class ReseedChecker {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_context.getBooleanProperty(Reseeder.PROP_DISABLE)) {
|
||||
if (_context.getBooleanProperty(Reseeder.PROP_DISABLE) ||
|
||||
_context.getBooleanProperty("i2p.vmCommSystem")) {
|
||||
int x = count - 1; // us
|
||||
// no ngettext, this is rare
|
||||
String s;
|
||||
|
||||
@@ -95,7 +95,7 @@ public class ClientAppConfig {
|
||||
/** @since 0.7.12 */
|
||||
public final String uninstallargs;
|
||||
/** @since 0.9.42 */
|
||||
private File configFile;
|
||||
File configFile;
|
||||
|
||||
public ClientAppConfig(String cl, String client, String a, long d, boolean dis) {
|
||||
this(cl, client, a, d, dis, null, null, null);
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.crypto.EncType;
|
||||
import net.i2p.crypto.KeyPair;
|
||||
import net.i2p.crypto.SigType;
|
||||
@@ -41,6 +42,7 @@ import net.i2p.router.util.EventLog;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* Warning - misnamed. This creates a new RouterIdentity, i.e.
|
||||
@@ -59,7 +61,9 @@ public class CreateRouterInfoJob extends JobImpl {
|
||||
/** @since 0.9.48 */
|
||||
static final String PROP_ROUTER_ENCTYPE = "router.encType";
|
||||
private static final SigType DEFAULT_SIGTYPE = SigType.EdDSA_SHA512_Ed25519;
|
||||
private static final EncType DEFAULT_ENCTYPE = EncType.ELGAMAL_2048;
|
||||
private static final EncType DEFAULT_ENCTYPE = (VersionComparator.comp(CoreVersion.VERSION, "0.9.49") >= 0) ?
|
||||
EncType.ECIES_X25519 :
|
||||
EncType.ELGAMAL_2048;
|
||||
|
||||
CreateRouterInfoJob(RouterContext ctx, Job next) {
|
||||
super(ctx);
|
||||
|
||||
@@ -36,7 +36,8 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
if (_loaded) return;
|
||||
_loaded = true;
|
||||
}
|
||||
List<ClientAppConfig> apps = ClientAppConfig.getClientApps(getContext());
|
||||
RouterContext ctx = getContext();
|
||||
List<ClientAppConfig> apps = ClientAppConfig.getClientApps(ctx);
|
||||
if (apps.isEmpty()) {
|
||||
_log.logAlways(Log.WARN, "Warning - No client apps or router console configured - we are just a router");
|
||||
System.err.println("Warning - No client apps or router console configured - we are just a router");
|
||||
@@ -47,7 +48,7 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
if (app.disabled) {
|
||||
if ("net.i2p.router.web.RouterConsoleRunner".equals(app.className)) {
|
||||
String s = "Warning - Router console is disabled. To enable,\n edit the file " +
|
||||
ClientAppConfig.configFile(getContext()) +
|
||||
(ClientAppConfig.isSplitConfig(ctx) ? app.configFile : ClientAppConfig.configFile(ctx)) +
|
||||
",\n change the line \"clientApp." + i + ".startOnLoad=false\"" +
|
||||
" to \"clientApp." + i + ".startOnLoad=true\",\n and restart.";
|
||||
_log.logAlways(Log.WARN, s);
|
||||
@@ -58,14 +59,14 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
String argVal[] = parseArgs(app.args);
|
||||
if (app.delay == 0) {
|
||||
// run this guy now
|
||||
runClient(app.className, app.clientName, argVal, getContext(), _log);
|
||||
runClient(app.className, app.clientName, argVal, ctx, _log);
|
||||
} else if (app.delay > 0) {
|
||||
// wait before firing it up
|
||||
DelayedRunClient drc = new DelayedRunClient(getContext().simpleTimer2(), getContext(), app.className,
|
||||
DelayedRunClient drc = new DelayedRunClient(ctx.simpleTimer2(), ctx, app.className,
|
||||
app.clientName, argVal);
|
||||
drc.schedule(app.delay);
|
||||
} else {
|
||||
WaitForRunningClient wfrc = new WaitForRunningClient(getContext().simpleTimer2(), getContext(),
|
||||
WaitForRunningClient wfrc = new WaitForRunningClient(ctx.simpleTimer2(), ctx,
|
||||
app.className, app.clientName, argVal);
|
||||
wfrc.schedule(1000);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class LoadRouterInfoJob extends JobImpl {
|
||||
private final Log _log;
|
||||
private RouterInfo _us;
|
||||
private static final AtomicBoolean _keyLengthChecked = new AtomicBoolean();
|
||||
// 1 chance in this many to rekey if the defaults changed
|
||||
private static final int REKEY_PROBABILITY = 128;
|
||||
|
||||
public LoadRouterInfoJob(RouterContext ctx) {
|
||||
super(ctx);
|
||||
@@ -126,13 +128,12 @@ class LoadRouterInfoJob extends JobImpl {
|
||||
if ((sigTypeChanged && getContext().getProperty(CreateRouterInfoJob.PROP_ROUTER_SIGTYPE) == null) ||
|
||||
(encTypeChanged && getContext().getProperty(CreateRouterInfoJob.PROP_ROUTER_ENCTYPE) == null)) {
|
||||
// Not explicitly configured, and default has changed
|
||||
// Give a 25% chance of rekeying for each restart
|
||||
// TODO reduce to ~3 (i.e. increase probability) in future release
|
||||
if (getContext().random().nextInt(16) > 0) {
|
||||
// Give a chance of rekeying for each restart
|
||||
if (getContext().random().nextInt(REKEY_PROBABILITY) > 0) {
|
||||
sigTypeChanged = false;
|
||||
encTypeChanged = false;
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Deferring RI rekey from " + stype + " to " + cstype);
|
||||
_log.warn("Deferring RI rekey from " + stype + '/' + etype + " to " + cstype + '/' + cetype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,22 +81,33 @@ public class WorkingDir {
|
||||
String home = System.getProperty("user.home");
|
||||
if (isWindows) {
|
||||
String appdata = System.getenv("LOCALAPPDATA");
|
||||
if (appdata != null)
|
||||
if (appdata != null) {
|
||||
home = appdata;
|
||||
}
|
||||
// Don't mess with existing Roaming Application Data installs,
|
||||
// in case somebody is using roaming appdata for a reason
|
||||
// already. In new installs, use local appdata by default. -idk
|
||||
appdata = System.getenv("APPDATA");
|
||||
if (appdata != null) {
|
||||
File checkOld = new File(appdata, WORKING_DIR_DEFAULT_WINDOWS);
|
||||
if (checkOld.exists() && checkOld.isDirectory())
|
||||
home = appdata;
|
||||
if (checkOld.exists() && checkOld.isDirectory()){
|
||||
File routerConfig = new File(checkOld.getAbsolutePath(), "router.config");
|
||||
// The Firefox profile installer was mistakenly using the Roaming application data
|
||||
// which is synced between devices on some Windows machines using MS cloud services,
|
||||
// instead of the local application data which is used by default.
|
||||
// It would create the router.config file in an empty directory, which the router would
|
||||
// then attempt to use, resulting in a router with no client applications. Checking
|
||||
// for clients.config.d determines if the directory is "Real" or not.
|
||||
File clientAppsConfig = new File(checkOld.getAbsolutePath(), "clients.config.d");
|
||||
if (routerConfig.exists() && clientAppsConfig.exists() && clientAppsConfig.isDirectory())
|
||||
home = appdata;
|
||||
}
|
||||
}
|
||||
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_WINDOWS);
|
||||
} else if (SystemVersion.isMac()) {
|
||||
String appdata = "/Library/Application Support/";
|
||||
File old = new File(home,WORKING_DIR_DEFAULT);
|
||||
if (old.exists() && old.isDirectory())
|
||||
File old = new File(home,WORKING_DIR_DEFAULT);
|
||||
if (old.exists() && old.isDirectory())
|
||||
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT);
|
||||
else {
|
||||
home = home+appdata;
|
||||
|
||||
@@ -33,7 +33,6 @@ import net.i2p.router.peermanager.DBHistory;
|
||||
import net.i2p.router.peermanager.PeerProfile;
|
||||
import net.i2p.router.tunnel.pool.TunnelPool;
|
||||
import net.i2p.router.util.HashDistance;
|
||||
import net.i2p.router.web.Messages;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateAverages;
|
||||
import net.i2p.stat.RateStat;
|
||||
@@ -41,6 +40,7 @@ import net.i2p.util.Addresses;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.ObjectCounter;
|
||||
import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -96,7 +96,8 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
public static final boolean DEFAULT_BLOCK = true;
|
||||
public static final double DEFAULT_BLOCK_THRESHOLD = 50.0;
|
||||
public static final long DEFAULT_BLOCK_TIME = 7*24*60*60*1000L;
|
||||
public static final long DEFAULT_REMOVE_TIME = 30*24*60*60*1000L;
|
||||
public static final long DEFAULT_REMOVE_TIME = 10*24*60*60*1000L;
|
||||
public static final long SHORT_REMOVE_TIME = 2*24*60*60*1000L;
|
||||
public static final long DEFAULT_FREQUENCY = 24*60*60*1000L;
|
||||
public static final float MIN_BLOCK_POINTS = 12.01f;
|
||||
|
||||
@@ -843,8 +844,10 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
return Util.biLog2(a);
|
||||
}
|
||||
|
||||
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
|
||||
|
||||
private String _t(String s) {
|
||||
return Messages.getString(s, _context);
|
||||
return Translate.getString(s, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -860,6 +863,6 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
* Use autoboxing to call with ints, longs, floats, etc.
|
||||
*/
|
||||
private String _t(String s, Object o) {
|
||||
return Messages.getString(s, o, _context);
|
||||
return Translate.getString(s, o, _context, BUNDLE_NAME);
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,12 @@ import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.router.web.helpers.SybilRenderer;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.FileSuffixFilter;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
@@ -180,7 +181,18 @@ public class PersistSybil {
|
||||
* @since 0.9.41
|
||||
*/
|
||||
public synchronized void removeOld() {
|
||||
long age = _context.getProperty(Analysis.PROP_REMOVETIME, Analysis.DEFAULT_REMOVE_TIME);
|
||||
// if we don't have a console, don't keep too many
|
||||
long removeTime = Analysis.SHORT_REMOVE_TIME;
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null) {
|
||||
ClientApp console = cmgr.getRegisteredApp("console");
|
||||
if (console != null)
|
||||
removeTime = Analysis.DEFAULT_REMOVE_TIME;
|
||||
}
|
||||
long age = _context.getProperty(Analysis.PROP_REMOVETIME, removeTime);
|
||||
long freq2 = 2 * _context.getProperty(Analysis.PROP_FREQUENCY, Analysis.DEFAULT_FREQUENCY);
|
||||
if (age < freq2)
|
||||
age = freq2;
|
||||
if (age < 60*1000)
|
||||
return;
|
||||
long cutoff = _context.clock().now() - age;
|
||||
@@ -5,5 +5,6 @@ store and load the results.
|
||||
</p>
|
||||
<p>
|
||||
Since 0.9.38.
|
||||
Moved from console to router in 0.9.49.
|
||||
</p>
|
||||
</body></html>
|
||||
@@ -87,7 +87,8 @@ public class RouterTimestamper extends Timestamper {
|
||||
// This means we no longer check every 5 minutes to see if we got enabled,
|
||||
// so the property must be set at startup.
|
||||
// We still need to be instantiated since the router calls clock().getTimestamper().waitForInitialization()
|
||||
_disabled = ctx.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
|
||||
_disabled = ctx.getProperty(PROP_DISABLED, DEFAULT_DISABLED) ||
|
||||
ctx.getBooleanProperty("i2p.vmCommSystem");
|
||||
if (_disabled) {
|
||||
_initialized = true;
|
||||
_zones = null;
|
||||
|
||||
@@ -213,6 +213,7 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
|
||||
private int receiveACKs(PeerState from, UDPPacketReader.DataReader data) throws DataFormatException {
|
||||
int rv = 0;
|
||||
boolean newAck = false;
|
||||
ModifiableLong highestSeqNumAcked = new ModifiableLong(-1);
|
||||
if (data.readACKsIncluded()) {
|
||||
int ackCount = data.readACKCount();
|
||||
if (ackCount > 0) {
|
||||
@@ -222,7 +223,7 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
|
||||
|
||||
for (int i = 0; i < ackCount; i++) {
|
||||
long id = data.readACK(i);
|
||||
if (from.acked(id)) {
|
||||
if (from.acked(id, highestSeqNumAcked)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("First full ACK of message " + id + " received from " + from.getRemotePeer());
|
||||
newAck = true;
|
||||
@@ -241,12 +242,10 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
|
||||
//_context.statManager().getStatLog().addData(from.getRemoteHostId().toString(), "udp.peer.receivePartialACKCount", bitfields.length, 0);
|
||||
|
||||
for (int i = 0; i < bitfields.length; i++) {
|
||||
if (from.acked(bitfields[i])) {
|
||||
if (from.acked(bitfields[i], highestSeqNumAcked)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Final partial ACK received: " + bitfields[i] + " from " + from.getRemotePeer());
|
||||
_log.debug("Partial ACK received: " + bitfields[i] + " from " + from.getRemotePeer());
|
||||
newAck = true;
|
||||
} else if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Partial ACK received: " + bitfields[i] + " from " + from.getRemotePeer());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,12 +255,30 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
|
||||
else
|
||||
from.dataReceived();
|
||||
|
||||
long highest = highestSeqNumAcked.value;
|
||||
if (highest >= 0) {
|
||||
boolean retx = from.highestSeqNumAcked(highest);
|
||||
if (retx)
|
||||
newAck = true;
|
||||
}
|
||||
|
||||
// Wake up the packet pusher if it is sleeping.
|
||||
// By calling add(), this also is a failsafe against possible
|
||||
// races in OutboundMessageFragments.
|
||||
/*
|
||||
if (newAck && from.getOutboundMessageCount() > 0)
|
||||
_outbound.add(from, 0);
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifiable Long, no locking
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public static class ModifiableLong {
|
||||
public long value;
|
||||
public ModifiableLong(long val) { value = val; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.i2p.router.transport.udp;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
@@ -38,9 +39,10 @@ class OutboundMessageState implements CDPQEntry {
|
||||
private int _maxSends;
|
||||
// we can't use the ones in _message since it is null for injections
|
||||
private long _enqueueTime;
|
||||
private long _seqNum;
|
||||
private volatile long _seqNum;
|
||||
/** how many bytes push() is allowed to send */
|
||||
private int _allowedSendBytes;
|
||||
private final AtomicInteger _nacks = new AtomicInteger();
|
||||
|
||||
public static final int MAX_MSG_SIZE = 32 * 1024;
|
||||
|
||||
@@ -114,6 +116,22 @@ class OutboundMessageState implements CDPQEntry {
|
||||
|
||||
public long getMessageId() { return _i2npMessage.getUniqueId(); }
|
||||
|
||||
/**
|
||||
* @return new value
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public int incrementNACKs() { return _nacks.incrementAndGet(); }
|
||||
|
||||
/**
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public int getNACKs() { return _nacks.get(); }
|
||||
|
||||
/**
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public void clearNACKs() { _nacks.set(0); }
|
||||
|
||||
public PeerState getPeer() { return _peer; }
|
||||
|
||||
public boolean isExpired() {
|
||||
@@ -489,6 +507,7 @@ class OutboundMessageState implements CDPQEntry {
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(256);
|
||||
buf.append("OB Message ").append(_i2npMessage.getUniqueId());
|
||||
buf.append(" seq ").append(_seqNum);
|
||||
buf.append(" type ").append(_i2npMessage.getType());
|
||||
buf.append(" size ").append(_messageBuf.length);
|
||||
if (_numFragments > 1)
|
||||
@@ -496,6 +515,8 @@ class OutboundMessageState implements CDPQEntry {
|
||||
buf.append(" volleys: ").append(_maxSends);
|
||||
buf.append(" lifetime: ").append(getLifetime());
|
||||
if (!isComplete()) {
|
||||
if (_nacks.get() > 0)
|
||||
buf.append(" NACKs: ").append(_nacks);
|
||||
if (_fragmentSends != null) {
|
||||
buf.append(" unacked fragments: ");
|
||||
for (int i = 0; i < _numFragments; i++) {
|
||||
|
||||
@@ -6,11 +6,13 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -18,6 +20,7 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.udp.InboundMessageFragments.ModifiableLong;
|
||||
import net.i2p.router.util.CachedIteratorCollection;
|
||||
import net.i2p.router.util.CoDelPriorityBlockingQueue;
|
||||
import net.i2p.router.util.PriBlockingQueue;
|
||||
@@ -176,6 +179,8 @@ public class PeerState {
|
||||
private int _packetsTransmitted;
|
||||
/** how many packets were retransmitted within the last RETRANSMISSION_PERIOD_WIDTH packets */
|
||||
private int _packetsRetransmitted;
|
||||
private long _nextSequenceNumber;
|
||||
private final AtomicBoolean _fastRetransmit = new AtomicBoolean();
|
||||
|
||||
/** how many dup packets were received within the last RETRANSMISSION_PERIOD_WIDTH packets */
|
||||
private int _packetsReceivedDuplicate;
|
||||
@@ -197,6 +202,8 @@ public class PeerState {
|
||||
*/
|
||||
//private final CoDelPriorityBlockingQueue<OutboundMessageState> _outboundQueue;
|
||||
private final PriBlockingQueue<OutboundMessageState> _outboundQueue;
|
||||
/** Message ID to sequence number */
|
||||
private final Map<Integer, Long> _ackedMessages;
|
||||
|
||||
/** when the retransmit timer is about to trigger */
|
||||
private long _retransmitTimer;
|
||||
@@ -297,18 +304,20 @@ public class PeerState {
|
||||
/**
|
||||
* The max number of acks we save to send as duplicates
|
||||
*/
|
||||
private static final int MAX_RESEND_ACKS = 64;
|
||||
private static final int MAX_RESEND_ACKS = 32;
|
||||
/**
|
||||
* The max number of duplicate acks sent in each ack-only messge.
|
||||
* Doesn't really matter, we have plenty of room...
|
||||
* @since 0.7.13
|
||||
*/
|
||||
private static final int MAX_RESEND_ACKS_LARGE = MAX_RESEND_ACKS / 3;
|
||||
private static final int MAX_RESEND_ACKS_LARGE = MAX_RESEND_ACKS * 2 / 3;
|
||||
/** for small MTU */
|
||||
private static final int MAX_RESEND_ACKS_SMALL = MAX_RESEND_ACKS / 5;
|
||||
private static final int MAX_RESEND_ACKS_SMALL = MAX_RESEND_ACKS * 2 / 5;
|
||||
|
||||
private static final long RESEND_ACK_TIMEOUT = 5*60*1000;
|
||||
private static final long RESEND_ACK_TIMEOUT = 60*1000;
|
||||
|
||||
/** if this many acks arrive out of order, fast rtx */
|
||||
private static final int FAST_RTX_ACKS = 3;
|
||||
|
||||
/**
|
||||
* @param rtt from the EstablishState, or 0 if not available
|
||||
@@ -356,6 +365,7 @@ public class PeerState {
|
||||
_outboundMessages = new CachedIteratorCollection<OutboundMessageState>();
|
||||
//_outboundQueue = new CoDelPriorityBlockingQueue(ctx, "UDP-PeerState", 32);
|
||||
_outboundQueue = new PriBlockingQueue<OutboundMessageState>(ctx, "UDP-PeerState", 32);
|
||||
_ackedMessages = new AckedMessages();
|
||||
// all createRateStat() moved to EstablishmentManager
|
||||
_remoteIP = remoteIP;
|
||||
_remotePeer = remotePeer;
|
||||
@@ -760,19 +770,26 @@ public class PeerState {
|
||||
// If we reduced the MTU, then we won't be able to send any previously-fragmented messages,
|
||||
// so set to the max MTU. This is the easiest fix, although it violates the RFC.
|
||||
//_sendWindowBytes = _mtu;
|
||||
_sendWindowBytes = isIPv6() ? MAX_IPV6_MTU : LARGE_MTU;
|
||||
int oldsst = _slowStartThreshold;
|
||||
float bwe = _bwEstimator.getBandwidthEstimate();
|
||||
_slowStartThreshold = Math.max( (int)(bwe * _rtt), 2 * _mtu);
|
||||
float bwe;
|
||||
if (_fastRetransmit.get()) {
|
||||
// window and SST set in highestSeqNumAcked()
|
||||
bwe = -1; // for log below
|
||||
} else {
|
||||
_sendWindowBytes = isIPv6() ? MAX_IPV6_MTU : LARGE_MTU;
|
||||
bwe = _bwEstimator.getBandwidthEstimate();
|
||||
_slowStartThreshold = Math.max( (int)(bwe * _rtt), 2 * _mtu);
|
||||
}
|
||||
|
||||
int oldRto = _rto;
|
||||
long oldTimer = _retransmitTimer - now;
|
||||
_rto = Math.min(MAX_RTO, Math.max(MIN_RTO, _rto << 1 ));
|
||||
_retransmitTimer = now + _rto;
|
||||
if (_log.shouldInfo())
|
||||
_log.info(_remotePeer + " Congestion, RTO: " + oldRto + " -> " + _rto + " timer: " + oldTimer + " -> " + (_retransmitTimer - now) +
|
||||
_log.info(_remotePeer + " Congestion, RTO: " + oldRto + " -> " + _rto + " timer: " + oldTimer + " -> " + _rto +
|
||||
" window: " + congestionAt + " -> " + _sendWindowBytes +
|
||||
" SST: " + oldsst + " -> " + _slowStartThreshold +
|
||||
" FRTX? " + _fastRetransmit +
|
||||
" BWE: " + DataHelper.formatSize2Decimal((long) (bwe * 1000), false) + "bps");
|
||||
}
|
||||
|
||||
@@ -1070,6 +1087,7 @@ public class PeerState {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(_remotePeer + " nothing pending, cancelling timer");
|
||||
_retransmitTimer = 0;
|
||||
exitFastRetransmit();
|
||||
} else {
|
||||
// any time new data gets acked, push out the timer
|
||||
long now = _context.clock().now();
|
||||
@@ -1313,6 +1331,8 @@ public class PeerState {
|
||||
boolean fail;
|
||||
synchronized (_outboundQueue) {
|
||||
fail = !_outboundQueue.offer(state);
|
||||
// reuse of CDPQ value, don't do both
|
||||
state.setSeqNum(_nextSequenceNumber++);
|
||||
}
|
||||
if (fail) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -1447,6 +1467,14 @@ public class PeerState {
|
||||
}
|
||||
// no need to nudge(), this is called from OMF loop before allocateSend()
|
||||
}
|
||||
if (rv <= 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(_remotePeer + " nothing pending, cancelling timer");
|
||||
synchronized(this) {
|
||||
_retransmitTimer = 0;
|
||||
exitFastRetransmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv + _outboundQueue.size();
|
||||
@@ -1475,6 +1503,9 @@ public class PeerState {
|
||||
_retransmitTimer = now + getRTO();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(_remotePeer + " allocated " + rv.size() + " pushing retransmitter from " + old + " to " + _retransmitTimer);
|
||||
} else if (_fastRetransmit.get()) {
|
||||
// right?
|
||||
_retransmitTimer = now + getRTO();
|
||||
}
|
||||
}
|
||||
} else if (canSendOld) {
|
||||
@@ -1484,10 +1515,12 @@ public class PeerState {
|
||||
isEmpty = _outboundMessages.isEmpty();
|
||||
}
|
||||
synchronized(this) {
|
||||
if (isEmpty)
|
||||
if (isEmpty) {
|
||||
_retransmitTimer = 0;
|
||||
else
|
||||
exitFastRetransmit();
|
||||
} else {
|
||||
_retransmitTimer = now + 250;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
@@ -1505,8 +1538,16 @@ public class PeerState {
|
||||
synchronized (_outboundMessages) {
|
||||
if (canSendOld) {
|
||||
for (OutboundMessageState state : _outboundMessages) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Allocate sending (OLD) to " + _remotePeer + ": " + state.getMessageId());
|
||||
if (_fastRetransmit.get()) {
|
||||
// If fast retx flag set, just add those
|
||||
if (state.getNACKs() < FAST_RTX_ACKS)
|
||||
continue;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Allocate sending (FAST) to " + _remotePeer + ": " + state);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Allocate sending (OLD) to " + _remotePeer + ": " + state.getMessageId());
|
||||
}
|
||||
if (rv == null) {
|
||||
rv = new ArrayList<OutboundMessageState>((1 + _outboundMessages.size()) / 2);
|
||||
_lastSendTime = now;
|
||||
@@ -1514,7 +1555,7 @@ public class PeerState {
|
||||
rv.add(state);
|
||||
// Retransmit up to half of the packets in flight (RFC 6298 section 5.4 and RFC 5681 section 4.3)
|
||||
// TODO this is fragments from half the messages... OK as is?
|
||||
if (rv.size() >= _outboundMessages.size() / 2)
|
||||
if (rv.size() >= _outboundMessages.size() / 2 && !_fastRetransmit.get())
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
@@ -1577,7 +1618,7 @@ public class PeerState {
|
||||
}
|
||||
if ( rv == null && _log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Nothing to send to " + _remotePeer + ", with " + _outboundMessages.size() +
|
||||
" / " + _outboundQueue.size() + " remaining, rtx timer in " + (_retransmitTimer - _context.clock().now()));
|
||||
" / " + _outboundQueue.size() + " remaining, rtx timer in " + (_retransmitTimer - now));
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -1589,14 +1630,14 @@ public class PeerState {
|
||||
*
|
||||
* @param now what time it is now
|
||||
* @return how long to wait before sending, or Integer.MAX_VALUE if we have nothing to send.
|
||||
* If ready now, will return 0 or a negative value.
|
||||
* If ready now, will return 0.
|
||||
*/
|
||||
int getNextDelay(long now) {
|
||||
int rv = Integer.MAX_VALUE;
|
||||
if (_dead) return rv;
|
||||
synchronized(this) {
|
||||
if (_retransmitTimer >= now)
|
||||
return (int) (_retransmitTimer - now);
|
||||
if (_retransmitTimer > 0)
|
||||
rv = Math.max(0, (int) (_retransmitTimer - now));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -1671,9 +1712,10 @@ public class PeerState {
|
||||
* A full ACK was received.
|
||||
* TODO if messages awaiting ack were a HashMap<Long, OutboundMessageState> this would be faster.
|
||||
*
|
||||
* @param highestSeqNumAcked in/out param, will modify if this seq. number is higher
|
||||
* @return true if the message was acked for the first time
|
||||
*/
|
||||
boolean acked(long messageId) {
|
||||
boolean acked(long messageId, ModifiableLong highestSeqNumAcked) {
|
||||
if (_dead) return false;
|
||||
OutboundMessageState state = null;
|
||||
boolean anyPending;
|
||||
@@ -1715,10 +1757,25 @@ public class PeerState {
|
||||
anyQueued = !_outboundQueue.isEmpty();
|
||||
}
|
||||
}
|
||||
long sn = state.getSeqNum();
|
||||
if (sn > highestSeqNumAcked.value)
|
||||
highestSeqNumAcked.value = sn;
|
||||
synchronized(_ackedMessages) {
|
||||
_ackedMessages.put(Integer.valueOf((int) messageId), Long.valueOf(sn));
|
||||
}
|
||||
// this adjusts the rtt/rto/window/etc
|
||||
messageACKed(state.getUnackedSize(), lifetime, numSends, anyPending, anyQueued);
|
||||
} else {
|
||||
// dupack, likely
|
||||
Long seq;
|
||||
synchronized(_ackedMessages) {
|
||||
seq = _ackedMessages.get(Integer.valueOf((int) messageId));
|
||||
}
|
||||
if (seq != null) {
|
||||
long sn = seq.longValue();
|
||||
if (sn > highestSeqNumAcked.value)
|
||||
highestSeqNumAcked.value = sn;
|
||||
}
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Received an ACK for a message not pending: " + messageId);
|
||||
}
|
||||
@@ -1728,15 +1785,16 @@ public class PeerState {
|
||||
/**
|
||||
* A partial ACK was received. This is much less common than full ACKs.
|
||||
*
|
||||
* @return true if the message was completely acked for the first time
|
||||
* @param highestSeqNumAcked in/out param, will modify if this seq. number is higher
|
||||
* @return true if any fragment of the message was completely acked for the first time
|
||||
*/
|
||||
boolean acked(ACKBitfield bitfield) {
|
||||
boolean acked(ACKBitfield bitfield, ModifiableLong highestSeqNumAcked) {
|
||||
if (_dead)
|
||||
return false;
|
||||
|
||||
final long messageId = bitfield.getMessageId();
|
||||
if (bitfield.receivedComplete()) {
|
||||
return acked(messageId);
|
||||
return acked(messageId, highestSeqNumAcked);
|
||||
}
|
||||
|
||||
OutboundMessageState state = null;
|
||||
@@ -1795,6 +1853,7 @@ public class PeerState {
|
||||
+ " for: " + state);
|
||||
}
|
||||
if (ackedSize > 0) {
|
||||
state.clearNACKs();
|
||||
boolean anyQueued;
|
||||
if (anyPending) {
|
||||
// locked_messageACKed will nudge()
|
||||
@@ -1807,15 +1866,119 @@ public class PeerState {
|
||||
// this adjusts the rtt/rto/window/etc
|
||||
messageACKed(ackedSize, lifetime, numSends, anyPending, anyQueued);
|
||||
}
|
||||
return isComplete;
|
||||
// we do this even if only partial
|
||||
long sn = state.getSeqNum();
|
||||
if (sn > highestSeqNumAcked.value)
|
||||
highestSeqNumAcked.value = sn;
|
||||
if (isComplete) {
|
||||
synchronized(_ackedMessages) {
|
||||
_ackedMessages.put(Integer.valueOf((int) messageId), Long.valueOf(sn));
|
||||
}
|
||||
}
|
||||
return ackedSize > 0;
|
||||
} else {
|
||||
// dupack
|
||||
Long seq;
|
||||
synchronized(_ackedMessages) {
|
||||
seq = _ackedMessages.get(Integer.valueOf((int) messageId));
|
||||
}
|
||||
if (seq != null) {
|
||||
long sn = seq.longValue();
|
||||
if (sn > highestSeqNumAcked.value)
|
||||
highestSeqNumAcked.value = sn;
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Received an ACK for a message not pending: " + bitfield);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter or leave fast retransmit mode, and adjust
|
||||
* SST and window variables accordingly.
|
||||
* See RFC 5681 sec. 2.4
|
||||
*
|
||||
* @param highest the highest sequence number that was acked
|
||||
* @return true if we have something to fast-retransmit
|
||||
* @since 0.9.49
|
||||
*/
|
||||
boolean highestSeqNumAcked(long highest) {
|
||||
boolean rv = false;
|
||||
boolean startFast = false;
|
||||
boolean continueFast = false;
|
||||
synchronized(_outboundMessages) {
|
||||
for (Iterator<OutboundMessageState> iter = _outboundMessages.iterator(); iter.hasNext(); ) {
|
||||
OutboundMessageState state = iter.next();
|
||||
long sn = state.getSeqNum();
|
||||
if (sn >= highest)
|
||||
break;
|
||||
if (sn < highest) {
|
||||
// this will also increment NACKs for a state that was just partially acked... ok?
|
||||
int nacks = state.incrementNACKs();
|
||||
if (nacks == FAST_RTX_ACKS) {
|
||||
startFast = true;
|
||||
rv = true;
|
||||
} else if (nacks > FAST_RTX_ACKS) {
|
||||
continueFast = true;
|
||||
rv = true;
|
||||
}
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Message NACKed: " + state);
|
||||
}
|
||||
}
|
||||
if (rv) {
|
||||
// set the variables for fast retransmit
|
||||
// timer will be reset below
|
||||
_fastRetransmit.set(true);
|
||||
// caller (IMF) will wakeup OMF
|
||||
if (continueFast) {
|
||||
// RFC 5681 sec. 3.2 #4 increase cwnd
|
||||
_sendWindowBytes += _mtu;
|
||||
_sendWindowBytesRemaining += _mtu;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Continue FAST RTX, inflated window: " + this);
|
||||
} else if (startFast) {
|
||||
// RFC 5681 sec. 3.2 #2 set SST (equation 4)
|
||||
// But use W+ BWE instead
|
||||
float bwe = _bwEstimator.getBandwidthEstimate();
|
||||
_slowStartThreshold = Math.max((int)(bwe * _rtt), 2 * _mtu);
|
||||
// RFC 5681 sec. 3.2 #3 set cwnd
|
||||
_sendWindowBytes = _slowStartThreshold + (3 * _mtu);
|
||||
_sendWindowBytesRemaining = _sendWindowBytes;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Start of FAST RTX, inflated window: " + this);
|
||||
}
|
||||
} else {
|
||||
exitFastRetransmit();
|
||||
}
|
||||
}
|
||||
if (rv) {
|
||||
synchronized(this) {
|
||||
_retransmitTimer = _context.clock().now();
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave fast retransmit mode if we were in it, and adjust
|
||||
* SST and window variables accordingly.
|
||||
* See RFC 5681 sec. 2.4
|
||||
*
|
||||
* @since 0.9.49
|
||||
*/
|
||||
private void exitFastRetransmit() {
|
||||
if (_fastRetransmit.compareAndSet(true, false)) {
|
||||
synchronized(this) {
|
||||
// RFC 5681 sec. 2.4 #6 deflate the window
|
||||
_sendWindowBytes = _slowStartThreshold;
|
||||
_sendWindowBytesRemaining = _sendWindowBytes;
|
||||
}
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("End of FAST RTX, deflated window: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer the basic activity/state from the old peer to the current peer
|
||||
*
|
||||
@@ -1894,6 +2057,19 @@ public class PeerState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message ID to sequence number.
|
||||
* Insertion order. Caller must synch.
|
||||
* @since 0.9.49
|
||||
*/
|
||||
private static class AckedMessages extends LinkedHashMap<Integer, Long> {
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<Integer, Long> eldest) {
|
||||
return size() > MAX_SEND_MSGS_PENDING;
|
||||
}
|
||||
}
|
||||
|
||||
// why removed? Some risk of dups in OutboundMessageFragments._activePeers ???
|
||||
|
||||
/*
|
||||
@@ -1932,8 +2108,12 @@ public class PeerState {
|
||||
buf.append(" sendAttemptAge: ").append(now-_lastSendTime);
|
||||
buf.append(" sendACKAge: ").append(now-_lastACKSend);
|
||||
buf.append(" lifetime: ").append(now-_keyEstablishedTime);
|
||||
buf.append(" RTT: ").append(_rtt);
|
||||
buf.append(" RTO: ").append(_rto);
|
||||
buf.append(" cwin: ").append(_sendWindowBytes);
|
||||
buf.append(" acwin: ").append(_sendWindowBytesRemaining);
|
||||
buf.append(" SST: ").append(_slowStartThreshold);
|
||||
buf.append(" FRTX? ").append(_fastRetransmit);
|
||||
buf.append(" consecFail: ").append(_consecutiveFailedSends);
|
||||
buf.append(" msgs rcvd: ").append(_messagesReceived);
|
||||
buf.append(" msgs sent: ").append(_messagesSent);
|
||||
|
||||
@@ -25,6 +25,7 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
// access outside lock on SBE to avoid deadlock
|
||||
private final PeerState _state;
|
||||
|
||||
private long _tAck;
|
||||
@@ -51,8 +52,14 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
* Records an arriving ack.
|
||||
* @param acked how many bytes were acked with this ack
|
||||
*/
|
||||
public synchronized void addSample(int acked) {
|
||||
public void addSample(int acked) {
|
||||
long now = _context.clock().now();
|
||||
// avoid deadlock
|
||||
int rtt = _state.getRTT();
|
||||
addSample(acked, now, rtt);
|
||||
}
|
||||
|
||||
private synchronized void addSample(int acked, long now, int rtt) {
|
||||
if (_acked < 0) {
|
||||
// first sample
|
||||
// use time since constructed as the RTT
|
||||
@@ -64,34 +71,38 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
_acked = 0;
|
||||
_tAck = now;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("first sample packets: " + acked + " deltaT: " + deltaT + ' ' + this);
|
||||
_log.debug("first sample bytes: " + acked + " deltaT: " + deltaT + ' ' + this);
|
||||
} else {
|
||||
_acked += acked;
|
||||
// anti-aliasing filter
|
||||
// As in kernel tcp_westwood.c
|
||||
// and the Westwood+ paper
|
||||
if (now - _tAck >= Math.max(_state.getRTT(), WESTWOOD_RTT_MIN))
|
||||
computeBWE(now);
|
||||
if (now - _tAck >= Math.max(rtt, WESTWOOD_RTT_MIN))
|
||||
computeBWE(now, rtt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current bandwidth estimate in bytes/ms.
|
||||
*/
|
||||
public synchronized float getBandwidthEstimate() {
|
||||
public float getBandwidthEstimate() {
|
||||
long now = _context.clock().now();
|
||||
// avoid deadlock
|
||||
int rtt = _state.getRTT();
|
||||
// anti-aliasing filter
|
||||
// As in kernel tcp_westwood.c
|
||||
// and the Westwood+ paper
|
||||
if (now - _tAck >= Math.max(_state.getRTT(), WESTWOOD_RTT_MIN))
|
||||
return computeBWE(now);
|
||||
return _bKFiltered;
|
||||
synchronized(this) {
|
||||
if (now - _tAck >= Math.max(rtt, WESTWOOD_RTT_MIN))
|
||||
return computeBWE(now, rtt);
|
||||
return _bKFiltered;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized float computeBWE(final long now) {
|
||||
private synchronized float computeBWE(final long now, final int rtt) {
|
||||
if (_acked < 0)
|
||||
return 0.0f; // nothing ever sampled
|
||||
updateBK(now, _acked);
|
||||
updateBK(now, _acked, rtt);
|
||||
_acked = 0;
|
||||
return _bKFiltered;
|
||||
}
|
||||
@@ -110,11 +121,13 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
* time-varying filter, as in kernel tcp_westwood.c
|
||||
*
|
||||
* @param time the time of the measurement
|
||||
* @param packets number of packets acked
|
||||
* @param packets number of bytes acked
|
||||
* @param rtt current rtt
|
||||
*/
|
||||
private void updateBK(long time, int packets) {
|
||||
private void updateBK(long time, int packets, int rtt) {
|
||||
long deltaT = time - _tAck;
|
||||
int rtt = Math.max(_state.getRTT(), WESTWOOD_RTT_MIN);
|
||||
if (rtt < WESTWOOD_RTT_MIN)
|
||||
rtt = WESTWOOD_RTT_MIN;
|
||||
if (deltaT > 2 * rtt) {
|
||||
// Decay with virtual null samples as in the Westwood paper
|
||||
int numrtts = Math.min((int) ((deltaT / rtt) - 1), 2 * DECAY_FACTOR);
|
||||
@@ -137,7 +150,7 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
}
|
||||
_tAck = time;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("computeBWE packets: " + packets + " deltaT: " + deltaT +
|
||||
_log.debug("computeBWE bytes: " + packets + " deltaT: " + deltaT +
|
||||
" bk/deltaT: " + bkdt + " _bK_ns_est: " + _bK_ns_est + ' ' + this);
|
||||
}
|
||||
|
||||
@@ -153,7 +166,7 @@ class SimpleBandwidthEstimator implements BandwidthEstimator {
|
||||
return "SBE[" +
|
||||
" _bKFiltered " + _bKFiltered +
|
||||
" _tAck " + _tAck + "; " +
|
||||
DataHelper.formatSize2Decimal((long) (_bKFiltered * 1000 * _state.getMTU()), false) +
|
||||
DataHelper.formatSize2Decimal((long) (_bKFiltered * 1000), false) +
|
||||
"Bps]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2455,7 +2455,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
// warning, this calls back into us with allowRebuildRouterInfo = false,
|
||||
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
|
||||
if (allowRebuildRouterInfo)
|
||||
_context.router().rebuildRouterInfo();
|
||||
rebuildRouterInfo();
|
||||
} else {
|
||||
addr = null;
|
||||
}
|
||||
@@ -2510,11 +2510,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
// warning, this calls back into us with allowRebuildRouterInfo = false,
|
||||
// via CSFI.createAddresses->TM.getAddresses()->updateAddress()->REA
|
||||
if (allowRebuildRouterInfo)
|
||||
_context.router().rebuildRouterInfo();
|
||||
rebuildRouterInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid deadlocks part 999
|
||||
* @since 0.9.49
|
||||
*/
|
||||
private void rebuildRouterInfo() {
|
||||
(new RebuildEvent()).schedule(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.49
|
||||
*/
|
||||
private class RebuildEvent extends SimpleTimer2.TimedEvent {
|
||||
/**
|
||||
* Caller must schedule
|
||||
*/
|
||||
public RebuildEvent() {
|
||||
super(_context.simpleTimer2());
|
||||
}
|
||||
public void timeReached() {
|
||||
_context.router().rebuildRouterInfo(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple fetch of stored IP and port, since
|
||||
* we don't put them in the real, published RouterAddress anymore
|
||||
|
||||
@@ -130,8 +130,8 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
||||
if (pool != null) {
|
||||
return pool.selectTunnel();
|
||||
}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Want the inbound tunnel for " + destination.toBase32() +
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Want the inbound tunnel for " + destination.toBase32() +
|
||||
" but there isn't a pool?", new Exception());
|
||||
return null;
|
||||
}
|
||||
@@ -206,8 +206,8 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
||||
if (pool != null) {
|
||||
return pool.selectTunnel(closestTo);
|
||||
}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Want the inbound tunnel for " + destination.toBase32() +
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Want the inbound tunnel for " + destination.toBase32() +
|
||||
" but there isn't a pool?", new Exception());
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,8 @@ include 'apps:jrobin'
|
||||
include 'apps:addressbook'
|
||||
include 'apps:susidns'
|
||||
include 'apps:susimail'
|
||||
include 'apps:i2pcontrol'
|
||||
include 'apps:imagegen'
|
||||
include 'core'
|
||||
include 'installer'
|
||||
include 'router'
|
||||
// TODO
|
||||
//include 'apps:i2pcontrol'
|
||||
//include 'apps:imagegen'
|
||||
|
||||
Reference in New Issue
Block a user