forked from I2P_Developers/i2p.i2p
Tunnels: Simplify TunnelId and HopConfig to save space
and reduce object churn and duplication Fixup tests, javadocs, logging as required
This commit is contained in:
@ -138,17 +138,19 @@ class TunnelRenderer {
|
||||
if (++displayed > DISPLAY_LIMIT)
|
||||
continue;
|
||||
out.write("<tr>");
|
||||
if (cfg.getReceiveTunnel() != null)
|
||||
long recv = cfg.getReceiveTunnelId();
|
||||
if (recv != 0)
|
||||
out.write("<td class=\"cells\" align=\"center\" title=\"" + _t("Tunnel identity") + "\"><span class=\"tunnel_id\">" +
|
||||
cfg.getReceiveTunnel().getTunnelId() + "</span></td>");
|
||||
recv + "</span></td>");
|
||||
else
|
||||
out.write("<td class=\"cells\" align=\"center\">n/a</td>");
|
||||
if (cfg.getReceiveFrom() != null)
|
||||
out.write("<td class=\"cells\" align=\"center\"><span class=\"tunnel_peer\">" + netDbLink(cfg.getReceiveFrom()) +"</span></td>");
|
||||
else
|
||||
out.write("<td class=\"cells\"> </td>");
|
||||
if (cfg.getSendTunnel() != null)
|
||||
out.write("<td class=\"cells\" align=\"center\" title=\"" + _t("Tunnel identity") + "\"><span class=\"tunnel_id\">" + cfg.getSendTunnel().getTunnelId() +"</span></td>");
|
||||
long send = cfg.getSendTunnelId();
|
||||
if (send != 0)
|
||||
out.write("<td class=\"cells\" align=\"center\" title=\"" + _t("Tunnel identity") + "\"><span class=\"tunnel_id\">" + send +"</span></td>");
|
||||
else
|
||||
out.write("<td class=\"cells\"> </td>");
|
||||
if (cfg.getSendTo() != null)
|
||||
|
@ -22,9 +22,15 @@ import java.io.OutputStream;
|
||||
* as the DatabaseStoreMessage uses a zero ID to request
|
||||
* a direct reply.
|
||||
*
|
||||
* 4 bytes, usually of random data.
|
||||
*
|
||||
* Not recommended for external use, subject to change.
|
||||
*
|
||||
* As of 0.9.48, does NOT extend DataStructureImpl, to save space
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class TunnelId extends DataStructureImpl {
|
||||
public class TunnelId {
|
||||
private long _tunnelId;
|
||||
|
||||
public static final long MAX_ID_VALUE = 0xffffffffL;
|
||||
@ -62,26 +68,6 @@ public class TunnelId extends DataStructureImpl {
|
||||
DataHelper.writeLong(out, 4, _tunnelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
*/
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return DataHelper.toLong(4, _tunnelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
* @param data non-null
|
||||
* @throws DataFormatException if null or wrong length
|
||||
*/
|
||||
@Override
|
||||
public void fromByteArray(byte data[]) throws DataFormatException {
|
||||
if (data == null) throw new DataFormatException("Null data passed in");
|
||||
if (data.length != 4) throw new DataFormatException("Bad data length");
|
||||
_tunnelId = (int) DataHelper.fromLong(data, 0, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
|
@ -16,9 +16,21 @@ package net.i2p.data;
|
||||
*/
|
||||
public class TunnelIdTest extends StructureTest {
|
||||
public DataStructure createDataStructure() throws DataFormatException {
|
||||
TunnelId id = new TunnelId();
|
||||
TunnelIdStructure id = new TunnelIdStructure();
|
||||
id.setTunnelId(42);
|
||||
return id;
|
||||
}
|
||||
public DataStructure createStructureToRead() { return new TunnelId(); }
|
||||
public DataStructure createStructureToRead() { return new TunnelIdStructure(); }
|
||||
|
||||
/**
|
||||
* so we can test it as a structure
|
||||
* @since 0.9.48 TunnelId no longer extends DataStructureImpl
|
||||
*/
|
||||
private class TunnelIdStructure extends TunnelId implements DataStructure {
|
||||
public Hash calculateHash() { return null; }
|
||||
public void fromByteArray(byte[] in) {}
|
||||
public byte[] toByteArray() { return null; }
|
||||
public void fromBase64(String in) {}
|
||||
public String toBase64() { return null; }
|
||||
}
|
||||
}
|
||||
|
@ -48,20 +48,24 @@ class BatchedRouterPreprocessor extends BatchedPreprocessor {
|
||||
|
||||
private static String getName(HopConfig cfg) {
|
||||
if (cfg == null) return "IB??";
|
||||
if (cfg.getReceiveTunnel() != null)
|
||||
return "IB " + cfg.getReceiveTunnel().getTunnelId();
|
||||
else if (cfg.getSendTunnel() != null)
|
||||
return "IB " + cfg.getSendTunnel().getTunnelId();
|
||||
long id = cfg.getReceiveTunnelId();
|
||||
if (id != 0)
|
||||
return "IB " + id;
|
||||
id = cfg.getSendTunnelId();
|
||||
if (id != 0)
|
||||
return "IB " + id;
|
||||
else
|
||||
return "IB??";
|
||||
}
|
||||
|
||||
private static String getName(TunnelCreatorConfig cfg) {
|
||||
if (cfg == null) return "OB??";
|
||||
if (cfg.getReceiveTunnelId(0) != null)
|
||||
return "OB " + cfg.getReceiveTunnelId(0).getTunnelId();
|
||||
else if (cfg.getSendTunnelId(0) != null)
|
||||
return "OB " + cfg.getSendTunnelId(0).getTunnelId();
|
||||
long id = cfg.getConfig(0).getReceiveTunnelId();
|
||||
if (id != 0)
|
||||
return "OB " + id;
|
||||
id = cfg.getConfig(0).getSendTunnelId();
|
||||
if (id != 0)
|
||||
return "OB " + id;
|
||||
else
|
||||
return "OB??";
|
||||
}
|
||||
|
@ -15,10 +15,8 @@ import net.i2p.data.TunnelId;
|
||||
* TunnelCreatorConfig to save space.
|
||||
*/
|
||||
public class HopConfig {
|
||||
private byte _receiveTunnelId[];
|
||||
private TunnelId _receiveTunnel;
|
||||
private Hash _receiveFrom;
|
||||
private byte _sendTunnelId[];
|
||||
private TunnelId _sendTunnel;
|
||||
private Hash _sendTo;
|
||||
private SessionKey _layerKey;
|
||||
@ -42,41 +40,67 @@ public class HopConfig {
|
||||
_expiration = -1;
|
||||
}
|
||||
|
||||
/** what tunnel ID are we receiving on? */
|
||||
public byte[] getReceiveTunnelId() { return _receiveTunnelId; }
|
||||
/**
|
||||
* What tunnel ID are we receiving on? (0 if uninitialized)
|
||||
*/
|
||||
public long getReceiveTunnelId() { return (_receiveTunnel != null) ? _receiveTunnel.getTunnelId() : 0; }
|
||||
|
||||
/**
|
||||
* What tunnel ID are we receiving on? (null if uninitialized)
|
||||
*/
|
||||
public TunnelId getReceiveTunnel() {
|
||||
if (_receiveTunnel == null)
|
||||
_receiveTunnel = getTunnel(_receiveTunnelId);
|
||||
return _receiveTunnel;
|
||||
}
|
||||
|
||||
public void setReceiveTunnelId(byte id[]) { _receiveTunnelId = id; }
|
||||
public void setReceiveTunnelId(TunnelId id) { _receiveTunnelId = DataHelper.toLong(4, id.getTunnelId()); }
|
||||
public void setReceiveTunnelId(TunnelId id) { _receiveTunnel = id; }
|
||||
|
||||
/**
|
||||
* @param id 1 to 0xffffffff
|
||||
* @throws IllegalArgumentException if less than or equal to zero or greater than max value
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public void setReceiveTunnelId(long id) { _receiveTunnel = new TunnelId(id); }
|
||||
|
||||
/** what is the previous peer in the tunnel (null if gateway) */
|
||||
public Hash getReceiveFrom() { return _receiveFrom; }
|
||||
|
||||
/**
|
||||
* Do not set for gateway
|
||||
*/
|
||||
public void setReceiveFrom(Hash from) { _receiveFrom = from; }
|
||||
|
||||
/** what is the next tunnel ID we are sending to? (null if endpoint) */
|
||||
public byte[] getSendTunnelId() { return _sendTunnelId; }
|
||||
/**
|
||||
* What is the next tunnel ID we are sending to? (0 if endpoint)
|
||||
*/
|
||||
public long getSendTunnelId() { return (_sendTunnel != null) ? _sendTunnel.getTunnelId() : 0; }
|
||||
|
||||
/** what is the next tunnel we are sending to? (null if endpoint) */
|
||||
/**
|
||||
* What is the next tunnel ID we are sending to? (null if endpoint)
|
||||
*/
|
||||
public TunnelId getSendTunnel() {
|
||||
if (_sendTunnel == null)
|
||||
_sendTunnel = getTunnel(_sendTunnelId);
|
||||
return _sendTunnel;
|
||||
}
|
||||
public void setSendTunnelId(byte id[]) { _sendTunnelId = id; }
|
||||
|
||||
private static TunnelId getTunnel(byte id[]) {
|
||||
if (id == null)
|
||||
return null;
|
||||
else
|
||||
return new TunnelId(DataHelper.fromLong(id, 0, id.length));
|
||||
}
|
||||
/**
|
||||
* Do not set for endpoint
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public void setSendTunnelId(TunnelId id) { _sendTunnel = id; }
|
||||
|
||||
/**
|
||||
* Do not set for endpoint
|
||||
* @param id 1 to 0xffffffff
|
||||
* @throws IllegalArgumentException if less than or equal to zero or greater than max value
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public void setSendTunnelId(long id) { _sendTunnel = new TunnelId(id); }
|
||||
|
||||
/** what is the next peer in the tunnel (null if endpoint) */
|
||||
public Hash getSendTo() { return _sendTo; }
|
||||
|
||||
/**
|
||||
* Do not set for endpoint
|
||||
*/
|
||||
public void setSendTo(Hash to) { _sendTo = to; }
|
||||
|
||||
/** what key should we use to encrypt the layer before passing it on? */
|
||||
@ -156,16 +180,16 @@ public class HopConfig {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
if (_receiveTunnelId != null) {
|
||||
if (_receiveTunnel != null) {
|
||||
buf.append("recv on ");
|
||||
buf.append(DataHelper.fromLong(_receiveTunnelId, 0, 4));
|
||||
buf.append(_receiveTunnel.getTunnelId());
|
||||
buf.append(' ');
|
||||
}
|
||||
|
||||
if (_sendTo != null) {
|
||||
buf.append("send to ").append(_sendTo.toBase64().substring(0,4)).append(":");
|
||||
if (_sendTunnelId != null)
|
||||
buf.append(DataHelper.fromLong(_sendTunnelId, 0, 4));
|
||||
if (_sendTunnel != null)
|
||||
buf.append(_sendTunnel.getTunnelId());
|
||||
}
|
||||
|
||||
buf.append(" exp. ").append(new Date(_expiration));
|
||||
|
@ -79,6 +79,6 @@ class OutboundTunnelEndpoint {
|
||||
/** @since 0.9.8 */
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OBEP " + _config.getReceiveTunnel();
|
||||
return "OBEP " + _config.getReceiveTunnelId();
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,6 @@ class ThrottledPumpedTunnelGateway extends PumpedTunnelGateway {
|
||||
/** @since 0.9.8 */
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IBGW " + _config.getReceiveTunnel();
|
||||
return "IBGW " + _config.getReceiveTunnelId();
|
||||
}
|
||||
}
|
||||
|
@ -96,12 +96,14 @@ public abstract class TunnelCreatorConfig implements TunnelInfo {
|
||||
* hop 0.
|
||||
*/
|
||||
public HopConfig getConfig(int hop) { return _config[hop]; }
|
||||
|
||||
/**
|
||||
* retrieve the tunnelId that the given hop receives messages on.
|
||||
* the gateway is hop 0.
|
||||
*
|
||||
*/
|
||||
public TunnelId getReceiveTunnelId(int hop) { return _config[hop].getReceiveTunnel(); }
|
||||
|
||||
/**
|
||||
* retrieve the tunnelId that the given hop sends messages on.
|
||||
* the gateway is hop 0.
|
||||
@ -354,13 +356,15 @@ public abstract class TunnelCreatorConfig implements TunnelInfo {
|
||||
for (int i = 0; i < _peers.length; i++) {
|
||||
buf.append(_peers[i].toBase64().substring(0,4));
|
||||
buf.append(isEC(i) ? " EC:" : " ElG:");
|
||||
if (_config[i].getReceiveTunnel() != null)
|
||||
buf.append(_config[i].getReceiveTunnel());
|
||||
long id = _config[i].getReceiveTunnelId();
|
||||
if (id != 0)
|
||||
buf.append(id);
|
||||
else
|
||||
buf.append("me");
|
||||
if (_config[i].getSendTunnel() != null) {
|
||||
id = _config[i].getSendTunnelId();
|
||||
if (id != 0) {
|
||||
buf.append('.');
|
||||
buf.append(_config[i].getSendTunnel());
|
||||
buf.append(id);
|
||||
} else if (_isInbound || i == 0) {
|
||||
buf.append(".me");
|
||||
}
|
||||
|
@ -392,13 +392,13 @@ public class TunnelDispatcher implements Service {
|
||||
* does not fully prevent joinOutbound() from failing later.
|
||||
* @since 0.9.5
|
||||
*/
|
||||
public long getNewOBGWID() {
|
||||
long rv;
|
||||
TunnelId tid;
|
||||
public TunnelId getNewOBGWID() {
|
||||
long id;
|
||||
TunnelId rv;
|
||||
do {
|
||||
rv = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
tid = new TunnelId(rv);
|
||||
} while (_outboundGateways.containsKey(tid));
|
||||
id = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
rv = new TunnelId(id);
|
||||
} while (_outboundGateways.containsKey(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -409,13 +409,13 @@ public class TunnelDispatcher implements Service {
|
||||
* does not fully prevent joinInbound() from failing later.
|
||||
* @since 0.9.5
|
||||
*/
|
||||
public long getNewIBEPID() {
|
||||
long rv;
|
||||
TunnelId tid;
|
||||
public TunnelId getNewIBEPID() {
|
||||
long id;
|
||||
TunnelId rv;
|
||||
do {
|
||||
rv = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
tid = new TunnelId(rv);
|
||||
} while (_participants.containsKey(tid));
|
||||
id = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
rv = new TunnelId(id);
|
||||
} while (_participants.containsKey(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -426,13 +426,13 @@ public class TunnelDispatcher implements Service {
|
||||
* does not fully prevent joinInbound() from failing later.
|
||||
* @since 0.9.5
|
||||
*/
|
||||
public long getNewIBZeroHopID() {
|
||||
long rv;
|
||||
TunnelId tid;
|
||||
public TunnelId getNewIBZeroHopID() {
|
||||
long id;
|
||||
TunnelId rv;
|
||||
do {
|
||||
rv = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
tid = new TunnelId(rv);
|
||||
} while (_inboundGateways.containsKey(tid));
|
||||
id = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
rv = new TunnelId(id);
|
||||
} while (_inboundGateways.containsKey(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -864,14 +864,14 @@ class BuildHandler implements Runnable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
cfg.setReceiveTunnelId(DataHelper.toLong(4, ourId));
|
||||
cfg.setReceiveTunnelId(ourId);
|
||||
if (isOutEnd) {
|
||||
// default
|
||||
//cfg.setSendTo(null);
|
||||
//cfg.setSendTunnelId(null);
|
||||
} else {
|
||||
cfg.setSendTo(nextPeer);
|
||||
cfg.setSendTunnelId(DataHelper.toLong(4, nextId));
|
||||
cfg.setSendTunnelId(nextId);
|
||||
}
|
||||
|
||||
// now "actually" join
|
||||
|
@ -89,18 +89,18 @@ abstract class BuildRequestor {
|
||||
if ( (!isIB) && (i == 0) ) {
|
||||
// outbound gateway (us) doesn't receive on a tunnel id
|
||||
if (len <= 1) { // zero hop, pretend to have a send id
|
||||
long id = ctx.tunnelDispatcher().getNewOBGWID();
|
||||
hop.setSendTunnelId(DataHelper.toLong(4, id));
|
||||
TunnelId id = ctx.tunnelDispatcher().getNewOBGWID();
|
||||
hop.setSendTunnelId(id);
|
||||
}
|
||||
} else {
|
||||
long id;
|
||||
TunnelId id;
|
||||
if (isIB && len == 1)
|
||||
id = ctx.tunnelDispatcher().getNewIBZeroHopID();
|
||||
else if (isIB && i == len - 1)
|
||||
id = ctx.tunnelDispatcher().getNewIBEPID();
|
||||
else
|
||||
id = 1 + ctx.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
hop.setReceiveTunnelId(DataHelper.toLong(4, id));
|
||||
id = new TunnelId(1 + ctx.random().nextLong(TunnelId.MAX_ID_VALUE));
|
||||
hop.setReceiveTunnelId(id);
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
|
@ -14,6 +14,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
/**
|
||||
@ -56,12 +57,12 @@ public class InboundTest extends TestCase {
|
||||
|
||||
private TunnelCreatorConfig prepareConfig(int numHops) {
|
||||
Hash peers[] = new Hash[numHops];
|
||||
byte tunnelIds[][] = new byte[numHops][4];
|
||||
long tunnelIds[] = new long[numHops];
|
||||
for (int i = 0; i < numHops; i++) {
|
||||
peers[i] = new Hash();
|
||||
peers[i].setData(new byte[Hash.HASH_LENGTH]);
|
||||
_context.random().nextBytes(peers[i].getData());
|
||||
_context.random().nextBytes(tunnelIds[i]);
|
||||
tunnelIds[i] = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
}
|
||||
|
||||
TunnelCreatorConfig config = new TCConfig(_context, numHops, false);
|
||||
@ -73,15 +74,10 @@ public class InboundTest extends TestCase {
|
||||
cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
|
||||
if (i > 0)
|
||||
cfg.setReceiveFrom(peers[i-1]);
|
||||
else
|
||||
cfg.setReceiveFrom(null);
|
||||
cfg.setReceiveTunnelId(tunnelIds[i]);
|
||||
if (i < numHops - 1) {
|
||||
cfg.setSendTo(peers[i+1]);
|
||||
cfg.setSendTunnelId(tunnelIds[i+1]);
|
||||
} else {
|
||||
cfg.setSendTo(null);
|
||||
cfg.setSendTunnelId(null);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
|
@ -12,6 +12,7 @@ import junit.framework.TestCase;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.router.RouterContext;
|
||||
|
||||
/**
|
||||
@ -55,12 +56,12 @@ public class OutboundTest extends TestCase{
|
||||
|
||||
private TunnelCreatorConfig prepareConfig(int numHops) {
|
||||
Hash peers[] = new Hash[numHops];
|
||||
byte tunnelIds[][] = new byte[numHops][4];
|
||||
long tunnelIds[] = new long[numHops];
|
||||
for (int i = 0; i < numHops; i++) {
|
||||
peers[i] = new Hash();
|
||||
peers[i].setData(new byte[Hash.HASH_LENGTH]);
|
||||
_context.random().nextBytes(peers[i].getData());
|
||||
_context.random().nextBytes(tunnelIds[i]);
|
||||
tunnelIds[i] = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
}
|
||||
|
||||
TunnelCreatorConfig config = new TCConfig(_context, numHops, false);
|
||||
@ -72,15 +73,10 @@ public class OutboundTest extends TestCase{
|
||||
cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
|
||||
if (i > 0)
|
||||
cfg.setReceiveFrom(peers[i-1]);
|
||||
else
|
||||
cfg.setReceiveFrom(null);
|
||||
cfg.setReceiveTunnelId(tunnelIds[i]);
|
||||
if (i < numHops - 1) {
|
||||
cfg.setSendTo(peers[i+1]);
|
||||
cfg.setSendTunnelId(tunnelIds[i+1]);
|
||||
} else {
|
||||
cfg.setSendTo(null);
|
||||
cfg.setSendTunnelId(null);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.i2p.router.tunnel;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.data.router.RouterIdentity;
|
||||
import net.i2p.data.router.RouterInfo;
|
||||
import net.i2p.router.Router;
|
||||
@ -34,12 +35,12 @@ public abstract class RouterITBase {
|
||||
|
||||
private static TunnelCreatorConfig prepareConfig(int numHops) {
|
||||
Hash peers[] = new Hash[numHops];
|
||||
byte tunnelIds[][] = new byte[numHops][4];
|
||||
long tunnelIds[] = new long[numHops];
|
||||
for (int i = 0; i < numHops; i++) {
|
||||
peers[i] = new Hash();
|
||||
peers[i].setData(new byte[Hash.HASH_LENGTH]);
|
||||
_context.random().nextBytes(peers[i].getData());
|
||||
_context.random().nextBytes(tunnelIds[i]);
|
||||
tunnelIds[i] = 1 + _context.random().nextLong(TunnelId.MAX_ID_VALUE);
|
||||
}
|
||||
|
||||
TunnelCreatorConfig config = new TCConfig(_context, numHops, false);
|
||||
@ -51,15 +52,10 @@ public abstract class RouterITBase {
|
||||
cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
|
||||
if (i > 0)
|
||||
cfg.setReceiveFrom(peers[i-1]);
|
||||
else
|
||||
cfg.setReceiveFrom(null);
|
||||
cfg.setReceiveTunnelId(tunnelIds[i]);
|
||||
if (i < numHops - 1) {
|
||||
cfg.setSendTo(peers[i+1]);
|
||||
cfg.setSendTunnelId(tunnelIds[i+1]);
|
||||
} else {
|
||||
cfg.setSendTo(null);
|
||||
cfg.setSendTunnelId(null);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
|
Reference in New Issue
Block a user