forked from I2P_Developers/i2p.i2p
Compare commits
12 Commits
tunnel-lim
...
sam-dg2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f932319781 | ||
![]() |
c04e1d6387 | ||
![]() |
79860f017f | ||
![]() |
383494fbf6 | ||
![]() |
31ce28621d | ||
![]() |
a36f1d2bba | ||
![]() |
f5db530c0e | ||
![]() |
502efa8349 | ||
![]() |
d4c660d863 | ||
![]() |
ec550dce0b | ||
![]() |
d2c3034a47 | ||
![]() |
2778bfd7c2 |
63
.github/workflows/ghcr.yml
vendored
Normal file
63
.github/workflows/ghcr.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
name: Create and publish a Docker image
|
||||
|
||||
# Cited: https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images
|
||||
|
||||
# Configures this workflow to run every time a change is pushed to the branch called `master`.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
#
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
|
||||
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository.
|
||||
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
|
||||
- name: Build and push Docker image
|
||||
id: push
|
||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
|
@@ -15,7 +15,7 @@ import net.i2p.data.Base32;
|
||||
*/
|
||||
public class MagnetURI {
|
||||
|
||||
private final String _tracker;
|
||||
private final List<String> _trackers;
|
||||
private final String _name;
|
||||
private final byte[] _ih;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class MagnetURI {
|
||||
public MagnetURI(I2PSnarkUtil util, String url) throws IllegalArgumentException {
|
||||
String ihash;
|
||||
String name;
|
||||
String trackerURL = null;
|
||||
List<String> trackerURLs = null;
|
||||
if (url.startsWith(MAGNET)) {
|
||||
// magnet:?xt=urn:btih:0691e40aae02e552cfcb57af1dca56214680c0c5&tr=http://tracker2.postman.i2p/announce.php
|
||||
String xt = getParam("xt", url);
|
||||
@@ -46,7 +46,7 @@ public class MagnetURI {
|
||||
if (xt == null || !xt.startsWith("urn:btih:"))
|
||||
throw new IllegalArgumentException();
|
||||
ihash = xt.substring("urn:btih:".length());
|
||||
trackerURL = getTrackerParam(url);
|
||||
trackerURLs = getTrackerParam(url);
|
||||
name = util.getString("Magnet") + ' ' + ihash;
|
||||
String dn = getParam("dn", url);
|
||||
if (dn != null)
|
||||
@@ -79,7 +79,7 @@ public class MagnetURI {
|
||||
throw new IllegalArgumentException();
|
||||
_ih = ih;
|
||||
_name = name;
|
||||
_tracker = trackerURL;
|
||||
_trackers = trackerURLs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,10 +97,18 @@ public class MagnetURI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tracker url or null
|
||||
* @return first valid tracker url or null
|
||||
*/
|
||||
public String getTrackerURL() {
|
||||
return _tracker;
|
||||
return _trackers != null ? _trackers.get(0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all valid tracker urls or null if none
|
||||
* @since 0.9.67 TODO to be hooked in via SnarkManager.addMagnet() and new Snark()
|
||||
*/
|
||||
public List<String> getTrackerURLs() {
|
||||
return _trackers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,26 +168,29 @@ public class MagnetURI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first valid I2P tracker or null
|
||||
* @return all valid I2P trackers or null if none
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private static String getTrackerParam(String uri) {
|
||||
private static List<String> getTrackerParam(String uri) {
|
||||
List<String> trackers = getMultiParam("tr", uri);
|
||||
if (trackers == null)
|
||||
return null;
|
||||
List<String> rv = new ArrayList<String>(trackers.size());
|
||||
for (String t : trackers) {
|
||||
try {
|
||||
URI u = new URI(t);
|
||||
String protocol = u.getScheme();
|
||||
String host = u.getHost();
|
||||
if (protocol == null || host == null ||
|
||||
!protocol.toLowerCase(Locale.US).equals("http") ||
|
||||
if (protocol == null || host == null)
|
||||
continue;
|
||||
protocol = protocol.toLowerCase(Locale.US);
|
||||
if (!(protocol.equals("http") || protocol.equals("udp")) ||
|
||||
!host.toLowerCase(Locale.US).endsWith(".i2p"))
|
||||
continue;
|
||||
return t;
|
||||
rv.add(t);
|
||||
} catch(URISyntaxException use) {}
|
||||
}
|
||||
return null;
|
||||
return rv.isEmpty() ? null : rv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -955,7 +955,7 @@ public class TrackerClient implements Runnable {
|
||||
long maxWait = fast ? 5*1000 : 60*1000;
|
||||
boolean small = left == 0 || event == UDPTrackerClient.EVENT_STOPPED || !coordinator.needOutboundPeers();
|
||||
int numWant = small ? 0 : _util.getMaxConnections();
|
||||
UDPTrackerClient.TrackerResponse fetched = udptc.announce(meta.getInfoHash(), snark.getID(), numWant,
|
||||
UDPTrackerClient.TrackerResponse fetched = udptc.announce(snark.getInfoHash(), snark.getID(), numWant,
|
||||
maxWait, tr.host, tr.port,
|
||||
downloaded, left, uploaded, event, fast);
|
||||
if (fast)
|
||||
|
@@ -794,6 +794,7 @@ class NetDbRenderer {
|
||||
buf.setLength(0);
|
||||
}
|
||||
} // for each
|
||||
buf.append("</div>");
|
||||
if (debug) {
|
||||
buf.append("<table id=\"leasesetdebug\"><tr><td><b>Network data (only valid if floodfill):</b></td><td colspan=\"3\">");
|
||||
//buf.append("</b></p><p><b>Center of Key Space (router hash): " + ourRKey.toBase64());
|
||||
@@ -811,7 +812,6 @@ class NetDbRenderer {
|
||||
}
|
||||
buf.append("</td></tr></table>\n");
|
||||
} // median table
|
||||
buf.append("</div>");
|
||||
} // !empty
|
||||
out.append(buf);
|
||||
out.flush();
|
||||
@@ -919,15 +919,17 @@ class NetDbRenderer {
|
||||
buf.append(dest.toBase64(), 0, 6);
|
||||
else
|
||||
buf.append("n/a");
|
||||
buf.append("</code></th>" +
|
||||
"</tr>\n<tr><td");
|
||||
if (!linkSusi)
|
||||
buf.append(" colspan=\"2\"");
|
||||
buf.append("><a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>\n");
|
||||
if (linkSusi && dest != null) {
|
||||
buf.append("<td class=\"addtobook\"><a title=\"").append(_t("Add to address book"))
|
||||
.append("\" href=\"/dns?book=private&destination=")
|
||||
.append(dest.toBase64()).append("#add\">").append(_t("Add to local address book")).append("</a></td>");
|
||||
buf.append("</code></th>");
|
||||
if (dest != null) {
|
||||
buf.append("</tr>\n<tr><td");
|
||||
if (!linkSusi)
|
||||
buf.append(" colspan=\"2\"");
|
||||
buf.append("><a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>\n");
|
||||
if (linkSusi) {
|
||||
buf.append("<td class=\"addtobook\"><a title=\"").append(_t("Add to address book"))
|
||||
.append("\" href=\"/dns?book=private&destination=")
|
||||
.append(dest.toBase64()).append("#add\">").append(_t("Add to local address book")).append("</a></td>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -954,7 +956,7 @@ class NetDbRenderer {
|
||||
buf.append(" <b>RAR?</b> ").append(ls.getReceivedAsReply());
|
||||
buf.append(" <b>Distance: </b>").append(distance);
|
||||
buf.append(" <b>").append(_t("Type")).append(": </b>").append(type);
|
||||
if (dest.isCompressible()) {
|
||||
if (dest != null && dest.isCompressible()) {
|
||||
buf.append(" <b>Compressible?</b> true");
|
||||
}
|
||||
if (type != DatabaseEntry.KEY_TYPE_LEASESET) {
|
||||
|
@@ -644,8 +644,8 @@ public class PeerHelper extends HelperBase {
|
||||
buf.setLength(0);
|
||||
long now = _context.clock().now();
|
||||
for (PeerState peer : peers) {
|
||||
if (now-peer.getLastReceiveTime() > 60*60*1000)
|
||||
continue; // don't include old peers
|
||||
//if (now-peer.getLastReceiveTime() > 60*60*1000)
|
||||
// continue; // don't include old peers
|
||||
|
||||
buf.append("<tr><td class=\"cells\" align=\"left\" nowrap>");
|
||||
buf.append(_context.commSystem().renderPeerHTML(peer.getRemotePeer()));
|
||||
|
@@ -23,6 +23,7 @@ import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -123,8 +124,11 @@ class PrimarySession extends SAMv3StreamSession implements SAMDatagramReceiver,
|
||||
if (spr != null) {
|
||||
try {
|
||||
listenProtocol = Integer.parseInt(spr);
|
||||
// RAW can't listen on streaming protocol
|
||||
// RAW can't listen on streaming or DG protocols
|
||||
if (listenProtocol < 0 || listenProtocol > 255 ||
|
||||
listenProtocol == I2PSession.PROTO_DATAGRAM ||
|
||||
listenProtocol == I2PSession.PROTO_DATAGRAM2 ||
|
||||
listenProtocol == I2PSession.PROTO_DATAGRAM3 ||
|
||||
listenProtocol == I2PSession.PROTO_STREAMING)
|
||||
return "Bad RAW LISTEN_PPROTOCOL " + spr;
|
||||
} catch (NumberFormatException nfe) {
|
||||
@@ -134,11 +138,23 @@ class PrimarySession extends SAMv3StreamSession implements SAMDatagramReceiver,
|
||||
SAMv3RawSession ssess = new SAMv3RawSession(nick, props, handler, isess, listenProtocol, listenPort, dgs);
|
||||
subhandler.setSession(ssess);
|
||||
sess = ssess;
|
||||
} else if (style.equals("DATAGRAM")) {
|
||||
} else if (style.equals("DATAGRAM") ||
|
||||
style.equals("DATAGRAM2") ||
|
||||
style.equals("DATAGRAM3")) {
|
||||
if (!props.containsKey("PORT"))
|
||||
return "DATAGRAM subsession must specify PORT";
|
||||
listenProtocol = I2PSession.PROTO_DATAGRAM;
|
||||
SAMv3DatagramSession ssess = new SAMv3DatagramSession(nick, props, handler, isess, listenPort, dgs);
|
||||
int v;
|
||||
if (style.equals("DATAGRAM")) {
|
||||
listenProtocol = I2PSession.PROTO_DATAGRAM;
|
||||
v = 1;
|
||||
} else if (style.equals("DATAGRAM2")) {
|
||||
listenProtocol = I2PSession.PROTO_DATAGRAM2;
|
||||
v = 2;
|
||||
} else {
|
||||
listenProtocol = I2PSession.PROTO_DATAGRAM3;
|
||||
v = 3;
|
||||
}
|
||||
SAMv3DatagramSession ssess = new SAMv3DatagramSession(nick, props, handler, isess, listenPort, dgs, v);
|
||||
subhandler.setSession(ssess);
|
||||
sess = ssess;
|
||||
} else if (style.equals("STREAM")) {
|
||||
@@ -212,6 +228,15 @@ class PrimarySession extends SAMv3StreamSession implements SAMDatagramReceiver,
|
||||
throw new IOException("primary session");
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IOException always
|
||||
* @since 0.9.68
|
||||
*/
|
||||
public void receiveDatagramBytes(Hash sender, byte[] data, int proto,
|
||||
int fromPort, int toPort) throws IOException {
|
||||
throw new IOException("primary session");
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
|
@@ -11,6 +11,7 @@ package net.i2p.sam;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
|
||||
/**
|
||||
* Interface for sending raw data to a SAM client
|
||||
@@ -29,6 +30,20 @@ interface SAMDatagramReceiver {
|
||||
*/
|
||||
public void receiveDatagramBytes(Destination sender, byte data[], int proto, int fromPort, int toPort) throws IOException;
|
||||
|
||||
/**
|
||||
* Send a byte array to a SAM client.
|
||||
* Only for Datagram3, where the sender Destination is not available, only the hash.
|
||||
*
|
||||
* @param sender Hash
|
||||
* @param data Byte array to be received
|
||||
* @param proto I2CP protocol, almost certainly 20 (DATAGRAM3)
|
||||
* @param fromPort I2CP from port
|
||||
* @param toPort I2CP to port
|
||||
* @since 0.9.68
|
||||
* @throws IOException
|
||||
*/
|
||||
public void receiveDatagramBytes(Hash sender, byte data[], int proto, int fromPort, int toPort) throws IOException;
|
||||
|
||||
/**
|
||||
* Stop receiving data.
|
||||
*
|
||||
|
@@ -12,17 +12,22 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.datagram.Datagram2;
|
||||
import net.i2p.client.datagram.Datagram3;
|
||||
import net.i2p.client.datagram.I2PDatagramDissector;
|
||||
import net.i2p.client.datagram.I2PDatagramMaker;
|
||||
import net.i2p.client.datagram.I2PInvalidDatagramException;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* SAM DATAGRAM session class.
|
||||
* Supports DG2/3 as of 0.9.68
|
||||
*
|
||||
* @author human
|
||||
*/
|
||||
@@ -33,28 +38,40 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
// FIXME make final after fixing SAMv3DatagramSession override
|
||||
protected SAMDatagramReceiver recv;
|
||||
private final I2PDatagramMaker dgramMaker;
|
||||
private final I2PDatagramDissector dgramDissector = new I2PDatagramDissector();
|
||||
private final I2PDatagramDissector dgramDissector;
|
||||
private final int version;
|
||||
|
||||
/**
|
||||
* Create a new SAM DATAGRAM session.
|
||||
* v1/v2 (DG1 only) or v3 (DG 1/2/3)
|
||||
*
|
||||
* @param dest Base64-encoded destination (private key)
|
||||
* @param props Properties to setup the I2P session
|
||||
* @param recv Object that will receive incoming data
|
||||
* @param v datagram version 1/2/3
|
||||
* @throws IOException
|
||||
* @throws DataFormatException
|
||||
* @throws I2PSessionException
|
||||
*/
|
||||
protected SAMDatagramSession(String dest, Properties props,
|
||||
SAMDatagramReceiver recv) throws IOException,
|
||||
SAMDatagramReceiver recv, int v) throws IOException,
|
||||
DataFormatException, I2PSessionException {
|
||||
super(dest, props);
|
||||
this.recv = recv;
|
||||
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||
if (v == 1) {
|
||||
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||
dgramDissector = new I2PDatagramDissector();
|
||||
} else if (v == 2 || v == 3) {
|
||||
dgramMaker = null;
|
||||
dgramDissector = null;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Bad version: " + v);
|
||||
}
|
||||
version = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SAM DATAGRAM session.
|
||||
* v1/v2 only, DG1 only
|
||||
*
|
||||
* Caller MUST call start().
|
||||
*
|
||||
@@ -64,27 +81,41 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
* @throws IOException
|
||||
* @throws DataFormatException
|
||||
* @throws I2PSessionException
|
||||
* @deprecated unused
|
||||
*/
|
||||
@Deprecated
|
||||
public SAMDatagramSession(InputStream destStream, Properties props,
|
||||
SAMDatagramReceiver recv) throws IOException,
|
||||
DataFormatException, I2PSessionException {
|
||||
super(destStream, props);
|
||||
this.recv = recv;
|
||||
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||
dgramDissector = new I2PDatagramDissector();
|
||||
version = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SAM DATAGRAM session on an existing I2P session.
|
||||
* v3 only, DG 1/2/3
|
||||
*
|
||||
* @param props unused for now
|
||||
* @param v datagram version 1/2/3
|
||||
* @since 0.9.25
|
||||
*/
|
||||
protected SAMDatagramSession(I2PSession sess, Properties props, int listenPort,
|
||||
SAMDatagramReceiver recv) throws IOException,
|
||||
SAMDatagramReceiver recv, int v) throws IOException,
|
||||
DataFormatException, I2PSessionException {
|
||||
super(sess, I2PSession.PROTO_DATAGRAM, listenPort);
|
||||
this.recv = recv;
|
||||
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||
if (v == 1) {
|
||||
dgramMaker = new I2PDatagramMaker(getI2PSession());
|
||||
dgramDissector = new I2PDatagramDissector();
|
||||
} else if (v == 2 || v == 3) {
|
||||
dgramMaker = null;
|
||||
dgramDissector = null;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Bad version: " + v);
|
||||
}
|
||||
version = v;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +123,7 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
*
|
||||
* @param dest Destination
|
||||
* @param data Bytes to be sent
|
||||
* @param proto ignored, will always use PROTO_DATAGRAM (17)
|
||||
* @param proto ignored, will always use PROTO_DATAGRAM (17), PROTO_DATAGRAM2 (19), or PROTO_DATAGRAM3 (20)
|
||||
*
|
||||
* @return True if the data was sent, false otherwise
|
||||
* @throws DataFormatException on unknown / bad dest
|
||||
@@ -102,16 +133,27 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
int fromPort, int toPort) throws DataFormatException, I2PSessionException {
|
||||
if (data.length > DGRAM_SIZE_MAX)
|
||||
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
|
||||
byte[] dgram ;
|
||||
synchronized (dgramMaker) {
|
||||
dgram = dgramMaker.makeI2PDatagram(data);
|
||||
byte[] dgram;
|
||||
if (version == 1) {
|
||||
synchronized (dgramMaker) {
|
||||
dgram = dgramMaker.makeI2PDatagram(data);
|
||||
}
|
||||
proto = I2PSession.PROTO_DATAGRAM;
|
||||
} else if (version == 2) {
|
||||
Hash h = new Destination(dest).calculateHash();
|
||||
dgram = Datagram2.make(I2PAppContext.getGlobalContext(), getI2PSession(), data, h);
|
||||
proto = I2PSession.PROTO_DATAGRAM2;
|
||||
} else {
|
||||
dgram = Datagram3.make(I2PAppContext.getGlobalContext(), getI2PSession(), data);
|
||||
proto = I2PSession.PROTO_DATAGRAM3;
|
||||
}
|
||||
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
|
||||
return sendBytesThroughMessageSession(dest, dgram, proto, fromPort, toPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send bytes through a SAM DATAGRAM session.
|
||||
*
|
||||
* @param proto ignored, will always use PROTO_DATAGRAM (17), PROTO_DATAGRAM2 (19), or PROTO_DATAGRAM3 (20)
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public boolean sendBytes(String dest, byte[] data, int proto,
|
||||
@@ -121,22 +163,50 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
throws DataFormatException, I2PSessionException {
|
||||
if (data.length > DGRAM_SIZE_MAX)
|
||||
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
|
||||
byte[] dgram ;
|
||||
synchronized (dgramMaker) {
|
||||
dgram = dgramMaker.makeI2PDatagram(data);
|
||||
byte[] dgram;
|
||||
if (version == 1) {
|
||||
synchronized (dgramMaker) {
|
||||
dgram = dgramMaker.makeI2PDatagram(data);
|
||||
}
|
||||
proto = I2PSession.PROTO_DATAGRAM;
|
||||
} else if (version == 2) {
|
||||
Hash h = new Destination(dest).calculateHash();
|
||||
dgram = Datagram2.make(I2PAppContext.getGlobalContext(), getI2PSession(), data, h);
|
||||
proto = I2PSession.PROTO_DATAGRAM2;
|
||||
} else {
|
||||
dgram = Datagram3.make(I2PAppContext.getGlobalContext(), getI2PSession(), data);
|
||||
proto = I2PSession.PROTO_DATAGRAM3;
|
||||
}
|
||||
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort,
|
||||
return sendBytesThroughMessageSession(dest, dgram, proto, fromPort, toPort,
|
||||
sendLeaseSet, sendTags,tagThreshold, expiration);
|
||||
}
|
||||
|
||||
protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) {
|
||||
byte[] payload;
|
||||
Destination sender;
|
||||
Hash h;
|
||||
try {
|
||||
synchronized (dgramDissector) {
|
||||
dgramDissector.loadI2PDatagram(msg);
|
||||
sender = dgramDissector.getSender();
|
||||
payload = dgramDissector.extractPayload();
|
||||
if (version == 1 && proto == I2PSession.PROTO_DATAGRAM) {
|
||||
synchronized (dgramDissector) {
|
||||
dgramDissector.loadI2PDatagram(msg);
|
||||
sender = dgramDissector.getSender();
|
||||
payload = dgramDissector.extractPayload();
|
||||
}
|
||||
h = null;
|
||||
} else if (version == 2 && proto == I2PSession.PROTO_DATAGRAM2) {
|
||||
Datagram2 dg = Datagram2.load(I2PAppContext.getGlobalContext(), getI2PSession(), msg);
|
||||
sender = dg.getSender();
|
||||
payload = dg.getPayload();
|
||||
h = null;
|
||||
} else if (version == 3 && proto == I2PSession.PROTO_DATAGRAM3) {
|
||||
Datagram3 dg = Datagram3.load(I2PAppContext.getGlobalContext(), getI2PSession(), msg);
|
||||
sender = null;
|
||||
payload = dg.getPayload();
|
||||
h = dg.getSender();
|
||||
} else {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Dropping mismatched protocol, datagram version=" + version + " proto=" + proto);
|
||||
return;
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
@@ -151,7 +221,13 @@ class SAMDatagramSession extends SAMMessageSession {
|
||||
}
|
||||
|
||||
try {
|
||||
recv.receiveDatagramBytes(sender, payload, proto, fromPort, toPort);
|
||||
if (sender != null) {
|
||||
// DG 1/2
|
||||
recv.receiveDatagramBytes(sender, payload, proto, fromPort, toPort);
|
||||
} else {
|
||||
// DG 3
|
||||
recv.receiveDatagramBytes(h, payload, proto, fromPort, toPort);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
_log.error("Error forwarding message to receiver", e);
|
||||
close();
|
||||
|
@@ -31,6 +31,7 @@ import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -277,7 +278,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
|
||||
rawSession = new SAMRawSession(destKeystream, props, this);
|
||||
rawSession.start();
|
||||
} else if (style.equals("DATAGRAM")) {
|
||||
datagramSession = new SAMDatagramSession(destKeystream, props,this);
|
||||
datagramSession = new SAMDatagramSession(destKeystream, props, this, 1);
|
||||
datagramSession.start();
|
||||
} else if (style.equals("STREAM")) {
|
||||
String dir = (String) props.remove("DIRECTION");
|
||||
@@ -829,6 +830,11 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
|
||||
writeBytes(ByteBuffer.wrap(msg.toByteArray()));
|
||||
}
|
||||
|
||||
public void receiveDatagramBytes(Hash sender, byte data[], int proto,
|
||||
int fromPort, int toPort) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void stopDatagramReceiving() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("stopDatagramReceiving() invoked");
|
||||
|
@@ -17,6 +17,7 @@ import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
|
||||
@@ -36,15 +37,17 @@ class SAMv3DatagramSession extends SAMDatagramSession implements Session, SAMDat
|
||||
* Caller MUST call start().
|
||||
*
|
||||
* @param nick nickname of the session
|
||||
* @param version datagram version 1/2/3
|
||||
* @throws IOException
|
||||
* @throws DataFormatException
|
||||
* @throws I2PSessionException
|
||||
*/
|
||||
public SAMv3DatagramSession(String nick, SAMv3DatagramServer dgServer)
|
||||
public SAMv3DatagramSession(String nick, SAMv3DatagramServer dgServer, int version)
|
||||
throws IOException, DataFormatException, I2PSessionException, SAMException {
|
||||
super(SAMv3Handler.sSessionsHash.get(nick).getDest(),
|
||||
SAMv3Handler.sSessionsHash.get(nick).getProps(),
|
||||
null // to be replaced by this
|
||||
null, // to be replaced by this
|
||||
version
|
||||
);
|
||||
this.nick = nick;
|
||||
this.recv = this; // replacement
|
||||
@@ -67,15 +70,16 @@ class SAMv3DatagramSession extends SAMDatagramSession implements Session, SAMDat
|
||||
* Caller MUST call start().
|
||||
*
|
||||
* @param nick nickname of the session
|
||||
* @param version datagram version 1/2/3
|
||||
* @throws IOException
|
||||
* @throws DataFormatException
|
||||
* @throws I2PSessionException
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public SAMv3DatagramSession(String nick, Properties props, SAMv3Handler handler, I2PSession isess,
|
||||
int listenPort, SAMv3DatagramServer dgServer)
|
||||
int listenPort, SAMv3DatagramServer dgServer, int version)
|
||||
throws IOException, DataFormatException, I2PSessionException {
|
||||
super(isess, props, listenPort, null); // to be replaced by this
|
||||
super(isess, props, listenPort, null, version); // to be replaced by this
|
||||
this.nick = nick ;
|
||||
this.recv = this ; // replacement
|
||||
this.server = dgServer;
|
||||
@@ -88,22 +92,43 @@ class SAMv3DatagramSession extends SAMDatagramSession implements Session, SAMDat
|
||||
if (this.clientAddress==null) {
|
||||
this.handler.receiveDatagramBytes(sender, data, proto, fromPort, toPort);
|
||||
} else {
|
||||
StringBuilder buf = new StringBuilder(600);
|
||||
buf.append(sender.toBase64());
|
||||
if ((handler.verMajor == 3 && handler.verMinor >= 2) || handler.verMajor > 3) {
|
||||
buf.append(" FROM_PORT=").append(fromPort).append(" TO_PORT=").append(toPort);
|
||||
}
|
||||
buf.append('\n');
|
||||
String msg = buf.toString();
|
||||
ByteBuffer msgBuf = ByteBuffer.allocate(msg.length()+data.length);
|
||||
msgBuf.put(DataHelper.getASCII(msg));
|
||||
msgBuf.put(data);
|
||||
// not ByteBuffer to avoid Java 8/9 issues with flip()
|
||||
((Buffer)msgBuf).flip();
|
||||
this.server.send(this.clientAddress, msgBuf);
|
||||
receiveDatagramBytes(sender.toBase64(), data, proto, fromPort, toPort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for Datagram3, where the sender Destination is not available, only the hash.
|
||||
* @since 0.9.68
|
||||
*/
|
||||
public void receiveDatagramBytes(Hash sender, byte[] data, int proto,
|
||||
int fromPort, int toPort) throws IOException {
|
||||
if (this.clientAddress==null) {
|
||||
this.handler.receiveDatagramBytes(sender, data, proto, fromPort, toPort);
|
||||
} else {
|
||||
receiveDatagramBytes(sender.toBase64(), data, proto, fromPort, toPort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.68 split out from above
|
||||
*/
|
||||
private void receiveDatagramBytes(String sender, byte[] data, int proto,
|
||||
int fromPort, int toPort) throws IOException {
|
||||
StringBuilder buf = new StringBuilder(600);
|
||||
buf.append(sender);
|
||||
if ((handler.verMajor == 3 && handler.verMinor >= 2) || handler.verMajor > 3) {
|
||||
buf.append(" FROM_PORT=").append(fromPort).append(" TO_PORT=").append(toPort);
|
||||
}
|
||||
buf.append('\n');
|
||||
String msg = buf.toString();
|
||||
ByteBuffer msgBuf = ByteBuffer.allocate(msg.length()+data.length);
|
||||
msgBuf.put(DataHelper.getASCII(msg));
|
||||
msgBuf.put(data);
|
||||
// not ByteBuffer to avoid Java 8/9 issues with flip()
|
||||
((Buffer)msgBuf).flip();
|
||||
this.server.send(this.clientAddress, msgBuf);
|
||||
}
|
||||
|
||||
public void stopDatagramReceiving() {
|
||||
}
|
||||
}
|
||||
|
@@ -500,10 +500,20 @@ class SAMv3Handler extends SAMv1Handler
|
||||
rawSession = v3;
|
||||
this.session = v3;
|
||||
v3.start();
|
||||
} else if (style.equals("DATAGRAM")) {
|
||||
} else if (style.equals("DATAGRAM") ||
|
||||
style.equals("DATAGRAM2") ||
|
||||
style.equals("DATAGRAM3")) {
|
||||
detector.start();
|
||||
SAMv3DatagramServer dgs = bridge.getV3DatagramServer(props);
|
||||
SAMv3DatagramSession v3 = new SAMv3DatagramSession(nick, dgs);
|
||||
int v;
|
||||
if (style.equals("DATAGRAM")) {
|
||||
v = 1;
|
||||
} else if (style.equals("DATAGRAM2")) {
|
||||
v = 2;
|
||||
} else {
|
||||
v = 3;
|
||||
}
|
||||
SAMv3DatagramSession v3 = new SAMv3DatagramSession(nick, dgs, v);
|
||||
datagramSession = v3;
|
||||
this.session = v3;
|
||||
v3.start();
|
||||
|
23
history.txt
23
history.txt
@@ -1,3 +1,26 @@
|
||||
2025-08-17 zzz
|
||||
* NetDB: Exploration improvements and fixes
|
||||
* Router: Fix PublishRouterInfoJob sometimes not getting started
|
||||
* SSU2: Fix last receive time tracking
|
||||
|
||||
2025-08-10 zzz
|
||||
* Console:
|
||||
- Hide b32 link on netdb LS tabs for encrypted LS
|
||||
- Fix layout for final LS data section on netdb LS debug tab
|
||||
* i2psnark: Handle UDP trackers in magnet links
|
||||
|
||||
2025-08-09 zzz
|
||||
* Console: Fix NPE on netdb LS debug tab rendering encrypted LS
|
||||
|
||||
2025-07-27 zzz
|
||||
* Crypto: Reduce YK precalc pool size
|
||||
* I2CP: Stub out new HostLookup types for service records (proposal 167)
|
||||
* i2ptunnel: Expose 6,4 option to non-advanced-config
|
||||
* Tomcat 9.0.107
|
||||
|
||||
2025-07-17 zzz
|
||||
* I2CP: Client-side destroy session fixes
|
||||
|
||||
2025-07-04 zzz
|
||||
* i2psnark: UDP announce fixes
|
||||
* SSU: Increase inbound ban time
|
||||
|
@@ -787,7 +787,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
synchronized(_configFileLock) {
|
||||
String f = getConfigFilename();
|
||||
Properties config = getConfig(_context, f);
|
||||
// to avoid compiler errror
|
||||
// to avoid compiler error
|
||||
Map foo = _config;
|
||||
foo.putAll(config);
|
||||
}
|
||||
@@ -956,23 +956,23 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed && _context.netDb().isInitialized()) {
|
||||
if (changed) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("NetDB ready, publishing RI");
|
||||
_log.warn("NetDB ready, initialized? " + _context.netDb().isInitialized());
|
||||
// any previous calls to netdb().publish() did not
|
||||
// actually publish, because netdb init was not complete
|
||||
Republish r = new Republish(_context);
|
||||
// this is called from PersistentDataStore.ReadJob,
|
||||
// so we probably don't need to throw it to the timer queue,
|
||||
// but just to be safe
|
||||
_context.simpleTimer2().addEvent(r, 0);
|
||||
long delay = _context.netDb().isInitialized() ? 0 : 60*1000;
|
||||
_context.simpleTimer2().addEvent(r, delay);
|
||||
|
||||
// periodically update our RI and republish it to the flooodfills
|
||||
PublishLocalRouterInfoJob plrij = new PublishLocalRouterInfoJob(_context);
|
||||
plrij.getTiming().setStartAfter(_context.clock().now() + plrij.getDelay());
|
||||
_context.jobQueue().addJob(plrij);
|
||||
}
|
||||
if (changed) {
|
||||
|
||||
_context.commSystem().initGeoIP();
|
||||
|
||||
if (!SystemVersion.isSlow() &&
|
||||
|
@@ -20,7 +20,7 @@ public class RouterVersion {
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
/** for example: "beta", "alpha", "rc" */
|
||||
public final static String QUALIFIER = "";
|
||||
public final static long BUILD = 5;
|
||||
public final static long BUILD = 7;
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
public final static String FULL_VERSION = VERSION + "-" + BUILD + QUALIFIER + EXTRA;
|
||||
|
@@ -131,7 +131,7 @@ class ExploreJob extends SearchJob {
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peers we don't want to hear about: " + dontIncludePeers);
|
||||
_log.debug("Search type: " + msg.getSearchType() + " exclude peers: " + dontIncludePeers);
|
||||
|
||||
msg.setDontIncludePeers(dontIncludePeers);
|
||||
|
||||
@@ -202,7 +202,6 @@ class ExploreJob extends SearchJob {
|
||||
* searchNext
|
||||
*
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String getName() { return "Kademlia NetDb Explore"; }
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ class StartExplorersJob extends JobImpl {
|
||||
The goal here is to avoid reseeding.
|
||||
*/
|
||||
/** very aggressively explore if we have less than this many routers */
|
||||
private static final int MIN_ROUTERS = 3 * KademliaNetworkDatabaseFacade.MIN_RESEED;
|
||||
private static final int MIN_ROUTERS = 5 * KademliaNetworkDatabaseFacade.MIN_RESEED;
|
||||
/** aggressively explore if we have less than this many routers */
|
||||
private static final int LOW_ROUTERS = 2 * MIN_ROUTERS;
|
||||
/** explore slowly if we have more than this many routers */
|
||||
@@ -54,7 +54,7 @@ class StartExplorersJob extends JobImpl {
|
||||
// must be lower than LIMIT_ROUTERS in HandleFloodfillDatabaseStoreMessageJob
|
||||
// because exploration does not register a reply job
|
||||
private static final int LIMIT_ROUTERS = SystemVersion.isSlow() ? 800 : 3000;
|
||||
private static final int MIN_FFS = 50;
|
||||
private static final int MIN_FFS = 100;
|
||||
static final int LOW_FFS = 2 * MIN_FFS;
|
||||
|
||||
private static final long MAX_LAG = 100;
|
||||
@@ -100,10 +100,16 @@ class StartExplorersJob extends JobImpl {
|
||||
boolean needffs = ffs < MIN_FFS;
|
||||
boolean lowffs = ffs < LOW_FFS;
|
||||
for (Hash key : toExplore) {
|
||||
// Last param false means get floodfills (non-explore)
|
||||
// false means get floodfills (non-explore)
|
||||
// This is very effective so we don't need to do it often
|
||||
boolean realexpl = !((needffs && getContext().random().nextInt(2) == 0) ||
|
||||
(lowffs && getContext().random().nextInt(4) == 0));
|
||||
boolean realexpl;
|
||||
if (needffs) {
|
||||
realexpl = getContext().random().nextInt(2) != 0;
|
||||
} else if (lowffs) {
|
||||
realexpl = getContext().random().nextInt(4) != 0;
|
||||
} else {
|
||||
realexpl = true;
|
||||
}
|
||||
ExploreJob j = new ExploreJob(getContext(), _facade, key, realexpl, _msgIDBloomXor);
|
||||
if (delay > 0)
|
||||
j.getTiming().setStartAfter(getContext().clock().now() + delay);
|
||||
|
@@ -211,14 +211,6 @@ public class FIFOBandwidthLimiter {
|
||||
return _refiller.getCurrentParticipatingBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* In Bytes per second
|
||||
* @since 0.9.68
|
||||
*/
|
||||
public int getMaxShareBandwidth() {
|
||||
return _refiller.getMaxShareBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request some bytes. Does not block.
|
||||
*/
|
||||
|
@@ -351,14 +351,6 @@ public class FIFOBandwidthRefiller implements Runnable {
|
||||
return (int) (_partBWE.getBandwidthEstimate() * 1000f);
|
||||
}
|
||||
|
||||
/**
|
||||
* In Bytes per second
|
||||
* @since 0.9.68
|
||||
*/
|
||||
int getMaxShareBandwidth() {
|
||||
return _partBWE != null ? _partBWE.getMaxBandwidth() : DEFAULT_OUTBOUND_BANDWIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a few times a minute to update the stats
|
||||
*
|
||||
|
@@ -226,6 +226,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void messagePartiallyReceived(long now) {
|
||||
setLastReceiveTime(now);
|
||||
if (_wantACKSendSince <= 0) {
|
||||
_wantACKSendSince = now;
|
||||
_ackTimer.schedule();
|
||||
|
@@ -15,7 +15,6 @@ import net.i2p.router.JobImpl;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* When a message arrives at the outbound tunnel endpoint, this distributor
|
||||
@@ -27,7 +26,6 @@ class OutboundMessageDistributor {
|
||||
private final Log _log;
|
||||
// following only for somebody else's OBEP, not for zero-hop
|
||||
private final Set<Hash> _toRouters;
|
||||
private final SyntheticREDQueue _partBWE;
|
||||
private int _newRouterCount;
|
||||
private long _newRouterTime;
|
||||
|
||||
@@ -41,16 +39,6 @@ class OutboundMessageDistributor {
|
||||
* OutNetMessage.PRIORITY_MY_DATA for our own zero-hop OBGW/EP
|
||||
*/
|
||||
public OutboundMessageDistributor(RouterContext ctx, int priority) {
|
||||
this(ctx, priority, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param priority OutNetMessage.PRIORITY_PARTICIPATING for somebody else's OBEP, or
|
||||
* OutNetMessage.PRIORITY_MY_DATA for our own zero-hop OBGW/EP
|
||||
* @param bwe null for none
|
||||
* @since 0.9.68
|
||||
*/
|
||||
public OutboundMessageDistributor(RouterContext ctx, int priority, SyntheticREDQueue bwe) {
|
||||
_context = ctx;
|
||||
_priority = priority;
|
||||
_log = ctx.logManager().getLog(OutboundMessageDistributor.class);
|
||||
@@ -60,7 +48,6 @@ class OutboundMessageDistributor {
|
||||
} else {
|
||||
_toRouters = null;
|
||||
}
|
||||
_partBWE = bwe;
|
||||
// all createRateStat() in TunnelDispatcher
|
||||
}
|
||||
|
||||
@@ -88,7 +75,7 @@ class OutboundMessageDistributor {
|
||||
if (_toRouters != null) {
|
||||
// only if not zero-hop
|
||||
// credit our lookup message as part. traffic
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.OBEP, DatabaseLookupMessage.MESSAGE_TYPE, 1024, _partBWE)) {
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.OBEP, DatabaseLookupMessage.MESSAGE_TYPE, 1024)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Drop msg at OBEP (lookup bandwidth) to " + target.toBase64() + " type " + msg.getType());
|
||||
return;
|
||||
|
@@ -11,7 +11,6 @@ import net.i2p.data.i2np.UnknownI2NPMessage;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* We are the end of an outbound tunnel that we did not create. Gather fragments
|
||||
@@ -25,7 +24,6 @@ class OutboundTunnelEndpoint {
|
||||
private final HopProcessor _processor;
|
||||
private final FragmentHandler _handler;
|
||||
private final OutboundMessageDistributor _outDistributor;
|
||||
private final SyntheticREDQueue _partBWE;
|
||||
|
||||
public OutboundTunnelEndpoint(RouterContext ctx, HopConfig config, HopProcessor processor) {
|
||||
_context = ctx;
|
||||
@@ -33,11 +31,7 @@ class OutboundTunnelEndpoint {
|
||||
_config = config;
|
||||
_processor = processor;
|
||||
_handler = new FragmentHandler(ctx, new DefragmentedHandler(), false);
|
||||
int max = _config.getAllocatedBW();
|
||||
if (max <= TunnelParticipant.DEFAULT_BW_PER_TUNNEL_ESTIMATE)
|
||||
max = _context.tunnelDispatcher().getMaxPerTunnelBandwidth(TunnelDispatcher.Location.OBEP);
|
||||
_partBWE = new SyntheticREDQueue(_context, max);
|
||||
_outDistributor = new OutboundMessageDistributor(ctx, OutNetMessage.PRIORITY_PARTICIPATING, _partBWE);
|
||||
_outDistributor = new OutboundMessageDistributor(ctx, OutNetMessage.PRIORITY_PARTICIPATING);
|
||||
}
|
||||
|
||||
public void dispatch(TunnelDataMessage msg, Hash recvFrom) {
|
||||
@@ -119,10 +113,9 @@ class OutboundTunnelEndpoint {
|
||||
int size = msg.getMessageSize();
|
||||
// don't drop it if we are the target
|
||||
boolean toUs = _context.routerHash().equals(toRouter);
|
||||
if (!toUs) {
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.OBEP, type, size, _partBWE))
|
||||
return;
|
||||
}
|
||||
if ((!toUs) &&
|
||||
_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.OBEP, type, size))
|
||||
return;
|
||||
// this overstates the stat somewhat, but ok for now
|
||||
//int kb = (size + 1023) / 1024;
|
||||
//for (int i = 0; i < kb; i++)
|
||||
|
@@ -4,7 +4,6 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* Same as PTG, but check to see if a message should be dropped before queueing it.
|
||||
@@ -15,16 +14,11 @@ import net.i2p.util.SyntheticREDQueue;
|
||||
class ThrottledPumpedTunnelGateway extends PumpedTunnelGateway {
|
||||
/** saved so we can note messages that get dropped */
|
||||
private final HopConfig _config;
|
||||
private final SyntheticREDQueue _partBWE;
|
||||
|
||||
public ThrottledPumpedTunnelGateway(RouterContext context, QueuePreprocessor preprocessor, Sender sender,
|
||||
Receiver receiver, TunnelGatewayPumper pumper, HopConfig config) {
|
||||
super(context, preprocessor, sender, receiver, pumper);
|
||||
_config = config;
|
||||
int max = _config.getAllocatedBW();
|
||||
if (max <= TunnelParticipant.DEFAULT_BW_PER_TUNNEL_ESTIMATE)
|
||||
max = _context.tunnelDispatcher().getMaxPerTunnelBandwidth(TunnelDispatcher.Location.IBGW);
|
||||
_partBWE = new SyntheticREDQueue(_context, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +43,7 @@ class ThrottledPumpedTunnelGateway extends PumpedTunnelGateway {
|
||||
// 2:1 batching of small messages
|
||||
size = 512;
|
||||
}
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.IBGW, msg.getType(), size, _partBWE)) {
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.IBGW, msg.getType(), size)) {
|
||||
// this overstates the stat somewhat, but ok for now
|
||||
int kb = (size + 1023) / 1024;
|
||||
for (int i = 0; i < kb; i++)
|
||||
|
@@ -29,7 +29,6 @@ import net.i2p.router.Service;
|
||||
import net.i2p.router.peermanager.PeerProfile;
|
||||
import net.i2p.router.tunnel.pool.PooledTunnelCreatorConfig;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* Handle the actual processing and forwarding of messages through the
|
||||
@@ -790,9 +789,8 @@ public class TunnelDispatcher implements Service {
|
||||
* @param loc message hop location
|
||||
* @param type I2NP message type
|
||||
* @param length the length of the message
|
||||
* @param bwe a per-tunnel bandwidth estimator to be checked first, or null
|
||||
*/
|
||||
boolean shouldDropParticipatingMessage(Location loc, int type, int length, SyntheticREDQueue bwe) {
|
||||
public boolean shouldDropParticipatingMessage(Location loc, int type, int length) {
|
||||
if (length <= 0)
|
||||
return false;
|
||||
|
||||
@@ -819,16 +817,6 @@ public class TunnelDispatcher implements Service {
|
||||
} else {
|
||||
factor = 1.0f;
|
||||
}
|
||||
|
||||
if (bwe != null) {
|
||||
if (!bwe.offer(length, factor)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Drop (per-tunnel) part. msg. factor=" + factor +
|
||||
' ' + loc + ' ' + type + ' ' + length + ' ' + bwe);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean reject = ! _context.bandwidthLimiter().sentParticipatingMessage(length, factor);
|
||||
if (reject) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
@@ -840,26 +828,6 @@ public class TunnelDispatcher implements Service {
|
||||
return reject;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum bandwidth for a single tunnel in Bps
|
||||
*
|
||||
* @param loc unused for now
|
||||
* @since 0.9.68
|
||||
*/
|
||||
int getMaxPerTunnelBandwidth(Location loc) {
|
||||
int max = _context.bandwidthLimiter().getMaxShareBandwidth();
|
||||
int maxTunnels = _context.getProperty(RouterThrottleImpl.PROP_MAX_TUNNELS, RouterThrottleImpl.DEFAULT_MAX_TUNNELS);
|
||||
if (maxTunnels > 25) {
|
||||
if (max >= 128*1024) // O/P/X
|
||||
max /= 16;
|
||||
else if (max <= 48*1024) // K/L
|
||||
max /= 4;
|
||||
else
|
||||
max = (12*1024) + ((max - (48*1024)) / 8); // M/N
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
//private static final int DROP_BASE_INTERVAL = 40 * 1000;
|
||||
//private static final int DROP_RANDOM_BOOST = 10 * 1000;
|
||||
|
||||
|
@@ -8,9 +8,7 @@ import net.i2p.data.i2np.TunnelDataMessage;
|
||||
import net.i2p.router.JobImpl;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.RouterThrottleImpl;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* Participate in a tunnel at a location other than the gateway or outbound
|
||||
@@ -27,15 +25,12 @@ class TunnelParticipant {
|
||||
private final InboundEndpointProcessor _inboundEndpointProcessor;
|
||||
private final InboundMessageDistributor _inboundDistributor;
|
||||
private final FragmentHandler _handler;
|
||||
private final SyntheticREDQueue _partBWE;
|
||||
private RouterInfo _nextHopCache;
|
||||
|
||||
private static final long MAX_LOOKUP_TIME = 15*1000;
|
||||
/** for next hop when a tunnel is first created */
|
||||
private static final long LONG_MAX_LOOKUP_TIME = 30*1000;
|
||||
private static final int PRIORITY = OutNetMessage.PRIORITY_PARTICIPATING;
|
||||
/** @since 0.9.68 from BuildHandler */
|
||||
static final int DEFAULT_BW_PER_TUNNEL_ESTIMATE = RouterThrottleImpl.DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE * 1024 / (10*60);
|
||||
|
||||
/** not an inbound endpoint */
|
||||
public TunnelParticipant(RouterContext ctx, HopConfig config, HopProcessor processor) {
|
||||
@@ -73,14 +68,6 @@ class TunnelParticipant {
|
||||
if (_nextHopCache == null)
|
||||
_context.netDb().lookupRouterInfo(_config.getSendTo(), new Found(_context), null, LONG_MAX_LOOKUP_TIME);
|
||||
}
|
||||
if (inEndProc == null) {
|
||||
int max = _config.getAllocatedBW();
|
||||
if (max <= DEFAULT_BW_PER_TUNNEL_ESTIMATE)
|
||||
max = _context.tunnelDispatcher().getMaxPerTunnelBandwidth(TunnelDispatcher.Location.PARTICIPANT);
|
||||
_partBWE = new SyntheticREDQueue(_context, max);
|
||||
} else {
|
||||
_partBWE = null;
|
||||
}
|
||||
// all createRateStat() in TunnelDispatcher
|
||||
}
|
||||
|
||||
@@ -213,7 +200,7 @@ class TunnelParticipant {
|
||||
|
||||
private void send(HopConfig config, TunnelDataMessage msg, RouterInfo ri) {
|
||||
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.PARTICIPANT,
|
||||
TunnelDataMessage.MESSAGE_TYPE, 1024, _partBWE))
|
||||
TunnelDataMessage.MESSAGE_TYPE, 1024))
|
||||
return;
|
||||
//_config.incrementSentMessages();
|
||||
long oldId = msg.getUniqueId();
|
||||
|
Reference in New Issue
Block a user