Compare commits

..

43 Commits

Author SHA1 Message Date
c0a0aa7700 Failed attempt to build debian package in docker
Keep running into

    debian-binary:
         [exec] dh patch --with systemd,bash-completion
         [exec] dpkg: warning: --compare-versions used with obsolete relation operator '>'
         [exec] dh: Unknown sequence patch (choose from: binary binary-arch binary-indep build build-arch build-indep clean install install-arch install-indep)
         [exec] make: *** [debian/rules:54: patch] Error 255
2021-01-23 22:43:51 +01:00
4a9131c39d CI: Add build_docker job conditions
We shouldn't build it for every single branch and commit
2021-01-23 22:37:29 +01:00
b47269f14e CI: Fix docker load command
It wasn't working at all which mean we would never use the cache
2021-01-23 22:36:56 +01:00
fb317b44ba CI: make sure we can build Docker image 2021-01-23 22:32:10 +01:00
e64e12b3fb Fix docker build
ant needed to be updated to >1.9, but the old image used an old alpine
 with the max version of ant being 1.8.

The build is split into 2 phases to reduce the size of the image.
A builder makes the installer and installs it in one image.
The installed files are copied over to the actual result image.
2021-01-23 18:19:31 +01:00
zzz
f71e59a049 Merge branch 'test-convert' into 'master'
Test net.i2p.util.ConvertToHash

See merge request i2p-hackers/i2p.i2p!13
2021-01-20 14:38:37 +00:00
169fb59d7d test: fix I2PSocketExceptionTest::testUnknownStatus
In non-English environments, the message is translated.
2021-01-20 14:38:37 +00:00
zzz
922178b2c7 SSU: Fix deadlock with router restart
http://zzz.i2p/topics/3036
2021-01-20 09:27:55 -05:00
zzz
74a9193ba5 Console: Fix link to UPnP status 2021-01-20 09:25:58 -05:00
idk
335409f1d2 Find and fix the bug which appears in 'https://old.reddit.com/r/i2p/search?q=console&restrict_sr=on&sort=relevance&t=all' a bunch of Reddit posts, due to a mistake in the Firefox Profile Installer which expected router.config to be in the (deprecated)Roaming application data, even though it was in the Local Application Data, and if it did not exist, created it. If the (deprecated)Roaming application data directory had a router.config file, then I2P attempted to use the Roaming application directory, and the user could end up with a router that had no client apps configured, resulting in a poor UX 2021-01-18 00:26:33 -05:00
idk
d6edb9e96c Merge branch 'gitlab-ci' into 'master'
Tests on Gitlab CI

See merge request i2p-hackers/i2p.i2p!12
2021-01-17 23:10:34 +00:00
f150855f1c test: fix I2PSocketExceptionTest::testUnknownStatus
In non-English environments, the message is translated.
2021-01-17 23:10:34 +00:00
zzz
655ce09796 Console: Remove echelon.i2p from home page at op's request 2021-01-17 10:06:44 -05:00
zzz
91ebec15d5 NetDB: log/stat tweak 2021-01-17 09:51:49 -05:00
zzz
b17d321503 Ratchet: log tweaks 2021-01-17 09:47:04 -05:00
zzz
a6398d88a9 i2psnark minor cleanup 2021-01-17 09:40:11 -05:00
zzz
59969db16c Sybil: Limit stored analysis files if no console to view them
Reduce stored file time to 10 days
Min stored time is 2 * analysis interval
2021-01-17 09:32:23 -05:00
zzz
b68a5ea7fd Router: Fix up warning about no console for split config files
clean up multiple getContext() calls
2021-01-17 09:18:21 -05:00
idk
c2234685b9 eepsite=>I2P site to match the new terminology on the web site, and more fine-tuning to CSS to sharpen image appearance 2021-01-17 01:11:51 -05:00
zzz
ce7daaa02a Router: Limit max addresses in RI 2021-01-14 10:32:35 -05:00
zzz
b19999f95a Router: Move Sybil subsystem from console to router 2021-01-14 09:46:38 -05:00
zzz
92ecc9f8e8 Router: Log crashed event if old router.ping file is found at startup 2021-01-14 09:25:21 -05:00
zzz
aa2ba92db8 Router: Change default encryption type to ECIES-X25519 (proposal 156)
As of 0.9.49. 0.9.48-x dev builds will not rekey.
New installs only.
Existing install rekey probability: 1 in 128
To be increased in later releases, see proposal 156 for details.
2021-01-14 08:54:17 -05:00
zzz
5f3c41244b Jetty: Fix URI in request logs
Use standard getRequestURI() instead of Jetty internal getHttpURI(),
which apparently changed somewhere along the way

Hide Jetty ClosedChannelException from I2P logs
2021-01-13 08:54:46 -05:00
zzz
bf29132898 Tunnels: Downgrade log error to warn 2021-01-12 09:49:09 -05:00
zzz
a424331b78 i2psnark: Don't decrement downloaded counter after receiving bad piece
Received reports of counter going negative
2021-01-12 08:23:36 -05:00
idk
ccb0c279f7 Fix the width of the custom options at the bottom of i2ptunnel on the light theme 2021-01-11 12:48:07 -05:00
zzz
7fe01fb9a7 Console: Delete rrd files for no-longer-configured stats at startup 2021-01-11 10:21:54 -05:00
zzz
66c4c10a78 Console: Improve parsing of email address (part 2) 2021-01-10 08:03:15 -05:00
zzz
163967311e Console: Improve parsing of email address for mailto: link on /plugins 2021-01-10 07:24:28 -05:00
zzz
75734448c5 I2NP: Stub out new tunnel build messages (proposal 157)
WIP - not hooked in yet
2021-01-09 12:00:18 -05:00
zzz
aed1de84b8 SSU: Fix bandwidth estimator deadlock (ticket #2798)
Fix logging in SBE (bytes not packets)
2021-01-08 12:07:41 -05:00
zzz
51560a8ec8 i2ptunnel: Disable shared clients (DSA) (part 2)
missed case in 2020-12-29 checkin
2021-01-08 11:27:53 -05:00
zzz
ec89a80e80 Router: Disable reseeding and NTP in vmCommSystem 2021-01-07 11:04:56 -05:00
zzz
41c7b7382a SSU: Implement fast retransmit (ticket #2427)
This partially fixes the issue of packets not being retransmitted
before they expire in 10 seconds, introduced in 0.9.48 as reported by
jogger at http://zzz.i2p/topics/3003
Fast retransmit was also suggested by jogger as a solution and discussed in that thread.
This code is based on the requirements for TCP fast retransmit
as specified in RFC 5681 but cannot precisely follow the RFC
as UDP messages can be dropped without affecting later messages:
- nack counter is per-message, not per-connection
- some interactions with the retransmit timer when in fast retx mode
- msg expiration is currently 10s but max RTO is 60s
- interactions with individual fragment transmission implemented in 0.9.48-5
- this is a sender-side fix but it depends on far-end ack resend strategy

Maintain a local message sequence number and store
it in OMF, previously unused as codel is disabled
Removed acked messages from _outboundMessages as usual,
but stores message and seq. numbers in a LinkedHashMap,
so we may interpret additional acks as nacks.
Calculate the highest-acked seq. number for every incoming packet.
Marks messages older than highest acked as nacked
Fast-retransmits after 3 nacks
Window and SST adjustments per RFC 5681 sec. 2.4
Reduce resend ack quantity and timeout to improve odds of receiving "nacks"
Disable wakeup of OMF from IMF; should not be needed now that PS calls nudge()
PS.acked(partial) now returns true if any fragment was acked, not if complete
Log tweaks

Still todo: possible additional changes to ack resend strategy;
possible parameter adjustments including msg expiration;
confirm that OMF wakeup in IMF is not required;
further testing and cleanups;
take additional ideas from alternative proposal in MR !8;
stat tweaks;
find related tickets to close

Reviewed by and contains code from zlatinb in MR !8
This builds on several previous SSU improvements; see #2427 for a list.
ref: gitlab MRs !8 !9 !10 !11
2021-01-07 09:33:09 -05:00
idk
b4e1fbd857 center the text on the force restart and shutdown buttons in the sidebar 2021-01-06 16:25:07 -05:00
zzz
517ff4fa24 i2psnark: Add ability to remove I2CP options
Properly lock options map
Remove unused configured variable
2021-01-05 11:21:04 -05:00
zzz
106b1a696d SusiDNS: Hide last-modified on details page if empty 2021-01-05 09:22:36 -05:00
zzz
6cab545c45 Console: Reduce limit of concurrent graph generation on slow devices 2021-01-05 09:18:25 -05:00
zzz
619923dbf8 Build: Update external javadoc links
Add description to gradle update tasks
Add note about jetty versions
2021-01-04 11:51:24 -05:00
zzz
ed0ecdf253 Build: Add gradle updater tasks 2021-01-04 09:36:34 -05:00
zzz
d42ef2223d Build: Add i2pcontrol and imagegen to gradle build 2021-01-04 08:34:09 -05:00
zzz
e461004ed9 Build: Remove jars from gradle wars 2021-01-04 07:38:19 -05:00
69 changed files with 1024 additions and 236 deletions

31
.dockerignore Normal file
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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')
}

View File

@@ -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]
*

View File

@@ -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
}

View File

@@ -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");

View File

@@ -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) {

View File

@@ -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>");

View File

@@ -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
}

View File

@@ -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 + "]");

View File

@@ -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)) {

View File

@@ -955,6 +955,7 @@ input.tunnelName, input.tunnelDescriptionText, #userAgents, .freetext.tunnelDesc
#customOptions {
margin-top: 15px !important;
width: 99%;
}
#tunnelDepth, #tunnelVariance, #tunnelQuantity, #tunnelBackupQuantity,

View File

@@ -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.")%>

View 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')
}

View File

@@ -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);

View File

@@ -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());

View File

@@ -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 \

View File

@@ -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) {

View File

@@ -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);
}
}
/**

View File

@@ -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();

View File

@@ -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;

View File

@@ -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"));

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -46,7 +46,7 @@
</td>
</tr>
<tr>
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%>&nbsp;<a href="peers#upnp">[<%=intl._t("UPnP Status")%>]</a></th>
<th id="upnpconfig"><%=intl._t("UPnP Configuration")%>&nbsp;<a href="peers?tx=upnp">[<%=intl._t("UPnP Status")%>]</a></th>
</tr>
<tr>
<td>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 B

View File

@@ -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"] {

View File

@@ -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>

View File

@@ -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.")%>

View File

@@ -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.")%>

View File

@@ -124,4 +124,4 @@ task codeCoverageReport(type: JacocoReport) {
}
}
//apply from: file('gradle/update.gradle')
apply from: file('gradle/update.gradle')

View File

@@ -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

View File

@@ -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" />

View 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"));
}
}

View File

@@ -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'
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 = "";

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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>

View File

@@ -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;

View File

@@ -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; }
}
}

View File

@@ -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++) {

View File

@@ -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&lt;Long, OutboundMessageState&gt; 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);

View File

@@ -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]";
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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'