RouterAddress:

- Add new constructor
 - Add add getHost() and deepEquals()
 - Compare host string, not IP, in equals()

SSU:
 - Remove all _external* fields; use _currentAddresses in super
 - Big rework of externalAddressReceived(), rebuildExternalAddress(),
   needsRebuild(), and replaceAddress() for multiple addresses and IPv6
 - Add caching in UDPAddress
 - More IPv6 flavors of utility methods
 - Remove two-art replaceAddress()
This commit is contained in:
zzz
2013-05-08 16:48:39 +00:00
parent af27c76b2c
commit 94e34ff366
6 changed files with 324 additions and 136 deletions

View File

@ -479,6 +479,21 @@ public abstract class TransportImpl implements Transport {
return _currentAddresses;
}
/**
* What address are we currently listening to?
* Replaces getCurrentAddress()
* @param ipv6 true for IPv6 only; false for IPv4 only
* @return first matching address or null
* @since IPv6
*/
public RouterAddress getCurrentAddress(boolean ipv6) {
for (RouterAddress ra : _currentAddresses) {
if (ipv6 == TransportUtil.isIPv6(ra))
return ra;
}
return null;
}
/**
* Do we have any current address?
* @since IPv6
@ -511,15 +526,9 @@ public abstract class TransportImpl implements Transport {
if (address == null) {
_currentAddresses.clear();
} else {
byte[] ip = address.getIP();
if (ip == null) {
_log.error("WTF null ip for " + address);
return;
}
int len = ip.length;
boolean isIPv6 = TransportUtil.isIPv6(address);
for (RouterAddress ra : _currentAddresses) {
byte[] ipx = ra.getIP();
if (ipx != null && ipx.length == len)
if (isIPv6 == TransportUtil.isIPv6(ra))
_currentAddresses.remove(ra);
}
_currentAddresses.add(address);

View File

@ -13,6 +13,7 @@ import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import net.i2p.data.RouterAddress;
import net.i2p.router.RouterContext;
/**
@ -78,6 +79,16 @@ public abstract class TransportUtil {
return IPv6Config.IPV6_DISABLED;
}
/**
* Addresses without a host (i.e. w/introducers)
* are assumed to be IPv4
*/
public static boolean isIPv6(RouterAddress addr) {
// do this the fast way, without calling getIP() to parse the host string
String host = addr.getOption(RouterAddress.PROP_HOST);
return host != null && host.contains(":");
}
/**
* @param addr non-null
* @since IPv6 moved from TransportImpl

View File

@ -447,7 +447,9 @@ class EstablishmentManager {
}
if (!_transport.allowConnection())
return; // drop the packet
state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getExternalPort(),
byte[] fromIP = from.getIP();
state = new InboundEstablishState(_context, fromIP, from.getPort(),
_transport.getExternalPort(fromIP.length == 16),
_transport.getDHBuilder());
state.receiveSessionRequest(reader.getSessionRequestReader());
InboundEstablishState oldState = _inboundStates.putIfAbsent(from, state);
@ -835,7 +837,9 @@ class EstablishmentManager {
_inboundStates.remove(state.getRemoteHostId());
return;
}
_transport.send(_builder.buildSessionCreatedPacket(state, _transport.getExternalPort(), _transport.getIntroKey()));
_transport.send(_builder.buildSessionCreatedPacket(state,
_transport.getExternalPort(state.getSentIP().length == 16),
_transport.getIntroKey()));
state.createdPacketSent();
}

View File

@ -2,10 +2,12 @@ package net.i2p.router.transport.udp;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import net.i2p.data.Base64;
import net.i2p.data.RouterAddress;
import net.i2p.data.SessionKey;
import net.i2p.util.LHMCache;
/**
* basic helper to parse out peer info from a udp address
@ -133,13 +135,8 @@ public class UDPAddress {
public String getHost() { return _host; }
InetAddress getHostAddress() {
if (_hostAddress == null) {
try {
_hostAddress = InetAddress.getByName(_host);
} catch (UnknownHostException uhe) {
_hostAddress = null;
}
}
if (_hostAddress == null)
_hostAddress = getByName(_host);
return _hostAddress;
}
@ -153,13 +150,8 @@ public class UDPAddress {
int getIntroducerCount() { return (_introAddresses == null ? 0 : _introAddresses.length); }
InetAddress getIntroducerHost(int i) {
if (_introAddresses[i] == null) {
try {
_introAddresses[i] = InetAddress.getByName(_introHosts[i]);
} catch (UnknownHostException uhe) {
_introAddresses[i] = null;
}
}
if (_introAddresses[i] == null)
_introAddresses[i] = getByName(_introHosts[i]);
return _introAddresses[i];
}
@ -197,4 +189,71 @@ public class UDPAddress {
}
return rv.toString();
}
////////////////
// cache copied from Addresses.java but caching InetAddress instead of byte[]
/**
* Textual IP to InetAddress, because InetAddress.getByName() is slow.
*
* @since IPv6
*/
private static final Map<String, InetAddress> _inetAddressCache;
static {
long maxMemory = Runtime.getRuntime().maxMemory();
if (maxMemory == Long.MAX_VALUE)
maxMemory = 96*1024*1024l;
long min = 128;
long max = 2048;
// 512 nominal for 128 MB
int size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
_inetAddressCache = new LHMCache(size);
}
/**
* Caching version of InetAddress.getByName(host), which is slow.
* Caches numeric host names only.
* Will resolve but not cache DNS host names.
*
* Unlike InetAddress.getByName(), we do NOT allow numeric IPs
* of the form d.d.d, d.d, or d, as these are almost certainly mistakes.
*
* @param host DNS or IPv4 or IPv6 host name; if null returns null
* @return InetAddress or null
* @since IPv6
*/
private static InetAddress getByName(String host) {
if (host == null)
return null;
InetAddress rv;
synchronized (_inetAddressCache) {
rv = _inetAddressCache.get(host);
}
if (rv == null) {
try {
boolean isIPv4 = host.replaceAll("[0-9\\.]", "").length() == 0;
if (isIPv4 && host.replaceAll("[0-9]", "").length() != 3)
return null;
rv = InetAddress.getByName(host);
if (isIPv4 ||
host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
synchronized (_inetAddressCache) {
_inetAddressCache.put(host, rv);
}
}
} catch (UnknownHostException uhe) {}
}
return rv;
}
/**
* @since IPv6
*/
static void clearCache() {
synchronized(_inetAddressCache) {
_inetAddressCache.clear();
}
}
}

View File

@ -45,6 +45,7 @@ import net.i2p.router.util.RandomIterator;
import net.i2p.util.Addresses;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
import net.i2p.util.SimpleTimer2;
@ -90,15 +91,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
/** do we need to rebuild our external router address asap? */
private boolean _needsRebuild;
/** summary info to distribute */
private RouterAddress _externalAddress;
/**
* Port number on which we can be reached, or -1 for error, or 0 for unset
* Do NOT use this for current internal port - use UDPEndpoint.getListenPort()
*/
private int _externalListenPort;
/** IP address of externally reachable host, or null */
private InetAddress _externalListenHost;
/** introduction key */
private SessionKey _introKey;
@ -332,7 +324,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// we will check below after starting up the endpoint.
int port;
int oldIPort = _context.getProperty(PROP_INTERNAL_PORT, -1);
int oldBindPort = getIPv4ListenPort();
int oldBindPort = getListenPort(false);
int oldEPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
if (oldIPort > 0)
port = oldIPort;
@ -387,7 +379,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// hack, first IPv4 endpoint, FIXME
if (newPort < 0 && endpoint.isIPv4()) {
newPort = endpoint.getListenPort();
_externalListenPort = newPort;
}
} catch (SocketException se) {
_endpoints.remove(endpoint);
@ -449,6 +440,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_dropList.clear();
_introManager.reset();
UDPPacket.clearCache();
UDPAddress.clearCache();
}
/**
@ -457,42 +449,62 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
*/
SessionKey getIntroKey() { return _introKey; }
int getExternalPort() { return _externalListenPort; }
int getExternalPort(boolean ipv6) {
RouterAddress addr = getCurrentAddress(ipv6);
if (addr != null) {
int rv = addr.getPort();
if (rv > 0)
return rv;
}
return getRequestedPort(ipv6);
}
/**
* IPv4 only
* @return IP or null
* @since 0.9.2
*/
byte[] getExternalIP() {
InetAddress ia = _externalListenHost;
if (ia == null)
return null;
return ia.getAddress();
RouterAddress addr = getCurrentAddress(false);
if (addr != null)
return addr.getIP();
return null;
}
/**
* The current port of the first IPv4 endpoint.
* To be enhanced to handle multiple IPv4 endpoints.
* The current port of the first matching endpoint.
* To be enhanced to handle multiple endpoints of the same type.
* @return port or -1
* @since IPv6
*/
private int getIPv4ListenPort() {
private int getListenPort(boolean ipv6) {
for (UDPEndpoint endpoint : _endpoints) {
if (endpoint.isIPv4())
if (((!ipv6) && endpoint.isIPv4()) ||
(ipv6 && endpoint.isIPv6()))
return endpoint.getListenPort();
}
return -1;
}
/**
* The current or configured internal IPv4 port.
* UDPEndpoint should always be instantiated (and a random port picked if not configured)
* before this is called, so the returned value should be > 0
* unless the endpoint failed to bind.
*/
@Override
public int getRequestedPort() {
return getRequestedPort(false);
}
/**
* The current or configured internal port.
* UDPEndpoint should always be instantiated (and a random port picked if not configured)
* before this is called, so the returned value should be > 0
* unless the endpoint failed to bind.
*/
@Override
public int getRequestedPort() {
int rv = getIPv4ListenPort();
private int getRequestedPort(boolean ipv6) {
int rv = getListenPort(ipv6);
if (rv > 0)
return rv;
// fallbacks
@ -604,7 +616,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
else
_log.warn("UPnP has failed to open the SSU port: " + port + " reason: " + reason);
}
if (success && _externalListenHost != null)
if (success && getExternalIP() != null)
setReachabilityStatus(CommSystemFacade.STATUS_OK);
}
@ -628,8 +640,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (ourIP.length != 4)
return;
boolean isValid = isValid(ourIP) &&
((ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT) ||
ourPort == _externalListenPort || _externalListenPort <= 0);
(ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT);
boolean explicitSpecified = explicitAddressSpecified();
boolean inboundRecent = _lastInboundReceivedOn + ALLOW_IP_CHANGE_INTERVAL > System.currentTimeMillis();
if (_log.shouldLog(Log.INFO))
@ -651,7 +662,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
markUnreachable(from);
//_context.banlist().banlistRouter(from, "They said we had an invalid IP", STYLE);
return;
} else if (inboundRecent && _externalListenPort > 0 && _externalListenHost != null) {
}
RouterAddress addr = getCurrentAddress(false);
if (inboundRecent && addr != null && addr.getPort() > 0 && addr.getHost() != null) {
// use OS clock since its an ordering thing, not a time thing
// Note that this fails us if we switch from one IP to a second, then back to the first,
// as some routers still have the first IP and will successfully connect,
@ -686,6 +699,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
/**
* Possibly change our external address to the IP/port.
* IP/port are already validated, but not yet compared to current IP/port.
* We compare here.
*
* @param ourIP MUST have been previously validated with isValid()
* IPv4 or IPv6 OK
* @param ourPort >= 1024 or 0 for no change
@ -696,39 +713,33 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
boolean updated = false;
boolean fireTest = false;
boolean isIPv6 = ourIP.length == 16;
RouterAddress current = getCurrentAddress(isIPv6);
byte[] externalListenHost = current != null ? current.getIP() : null;
int externalListenPort = current != null ? current.getPort() : getRequestedPort(isIPv6);
if (_log.shouldLog(Log.INFO))
_log.info("Change address? status = " + _reachabilityStatus +
" diff = " + (_context.clock().now() - _reachabilityStatusLastUpdated) +
" old = " + _externalListenHost + ':' + _externalListenPort +
" old = " + Addresses.toString(externalListenHost, externalListenPort) +
" new = " + Addresses.toString(ourIP, ourPort));
if ((fixedPort && externalListenPort > 0) || ourPort <= 0)
ourPort = externalListenPort;
synchronized (this) {
if ( (_externalListenHost == null) ||
(!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) {
if (ourPort > 0 &&
!eq(externalListenHost, externalListenPort, ourIP, ourPort)) {
// This prevents us from changing our IP when we are not firewalled
//if ( (_reachabilityStatus != CommSystemFacade.STATUS_OK) ||
// (_externalListenHost == null) || (_externalListenPort <= 0) ||
// (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) {
// they told us something different and our tests are either old or failing
try {
_externalListenHost = InetAddress.getByAddress(ourIP);
// fixed port defaults to true so we never do this
if (ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT && !fixedPort)
_externalListenPort = ourPort;
if (_log.shouldLog(Log.WARN))
_log.warn("Trying to change our external address to " +
Addresses.toString(ourIP, _externalListenPort));
if (_externalListenPort > 0) {
rebuildExternalAddress();
replaceAddress(_externalAddress);
updated = true;
}
} catch (UnknownHostException uhe) {
_externalListenHost = null;
if (_log.shouldLog(Log.WARN))
_log.warn("Error trying to change our external address to " +
Addresses.toString(ourIP, ourPort), uhe);
}
Addresses.toString(ourIP, ourPort));
RouterAddress newAddr = rebuildExternalAddress(ourIP, ourPort, true);
updated = newAddr != null;
//} else {
// // they told us something different, but our tests are recent and positive,
// // so lets test again
@ -748,13 +759,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} else if (updated) {
_context.statManager().addRateData("udp.addressUpdated", 1);
Map<String, String> changes = new HashMap();
if (!fixedPort)
if (ourIP.length == 4 && !fixedPort)
changes.put(PROP_EXTERNAL_PORT, Integer.toString(ourPort));
// queue a country code lookup of the new IP
_context.commSystem().queueLookup(ourIP);
if (ourIP.length == 4)
_context.commSystem().queueLookup(ourIP);
// store these for laptop-mode (change ident on restart... or every time... when IP changes)
// IPV4 ONLY
String oldIP = _context.getProperty(PROP_IP);
if (!_externalListenHost.getHostAddress().equals(oldIP)) {
String newIP = Addresses.toString(ourIP);
if (ourIP.length == 4 && !newIP.equals(oldIP)) {
long lastChanged = 0;
long now = _context.clock().now();
String lcs = _context.getProperty(PROP_IP_CHANGE);
@ -764,7 +778,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} catch (NumberFormatException nfe) {}
}
changes.put(PROP_IP, _externalListenHost.getHostAddress());
changes.put(PROP_IP, newIP);
changes.put(PROP_IP_CHANGE, Long.toString(now));
_context.router().saveConfig(changes, null);
@ -784,7 +798,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.router().shutdown(Router.EXIT_HARD_RESTART);
// doesn't return
}
} else if (!fixedPort) {
} else if (ourIP.length == 4 && !fixedPort) {
// save PROP_EXTERNAL_PORT
_context.router().saveConfig(changes, null);
}
@ -795,6 +809,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return updated;
}
/**
* @param laddr and raddr may be null
*/
private static final boolean eq(byte laddr[], int lport, byte raddr[], int rport) {
return (rport == lport) && DataHelper.eq(laddr, raddr);
}
@ -839,12 +856,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
/**
* Get the states for all peers at the given remote host, ignoring port.
* Used for a last-chance search for a peer that changed port, by PacketHandler.
* Always returns empty list for IPv6 hostInfo.
* @since 0.9.3
*/
List<PeerState> getPeerStatesByIP(RemoteHostId hostInfo) {
List<PeerState> rv = new ArrayList(4);
byte[] ip = hostInfo.getIP();
if (ip != null) {
if (ip != null && ip.length == 4) {
for (PeerState ps : _peersByIdent.values()) {
if (DataHelper.eq(ip, ps.getRemoteIP()))
rv.add(ps);
@ -865,7 +883,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
* Remove and add to peersByRemoteHost map
* @since 0.9.3
*/
public void changePeerPort(PeerState peer, int newPort) {
void changePeerPort(PeerState peer, int newPort) {
int oldPort;
synchronized (_addDropLock) {
oldPort = peer.getRemotePort();
@ -887,6 +905,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
EstablishmentManager getEstablisher() {
return _establisher;
}
/**
* Intercept RouterInfo entries received directly from a peer to inject them into
* the PeersByCapacity listing.
@ -1216,11 +1235,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if ( (altByHost != null) && (peer != altByHost) ) locked_dropPeer(altByHost, shouldBanlist, "recurse");
}
/**
* Does the IPv4 external address need to be rebuilt?
*/
private boolean needsRebuild() {
if (_needsRebuild) return true; // simple enough
if (_context.router().isHidden()) return false;
RouterAddress addr = getCurrentAddress(false);
if (introducersRequired()) {
RouterAddress addr = _externalAddress;
UDPAddress ua = new UDPAddress(addr);
int valid = 0;
for (int i = 0; i < ua.getIntroducerCount(); i++) {
@ -1246,26 +1268,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return true;
}
} else {
boolean rv = (_externalListenHost == null) || (_externalListenPort <= 0);
byte[] externalListenHost = addr != null ? addr.getIP() : null;
int externalListenPort = addr != null ? addr.getPort() : -1;
boolean rv = (externalListenHost == null) || (externalListenPort <= 0);
if (!rv) {
RouterAddress addr = _externalAddress;
UDPAddress ua = new UDPAddress(addr);
if (ua.getIntroducerCount() > 0)
// shortcut to determine if introducers are present
if (addr.getOption("ihost0") != null)
rv = true; // status == ok and we don't actually need introducers, so rebuild
}
if (_log.shouldLog(Log.INFO)) {
if (rv) {
_log.info("Need to initialize our direct SSU info (" + _externalListenHost + ":" + _externalListenPort + ")");
} else {
RouterAddress addr = _externalAddress;
UDPAddress ua = new UDPAddress(addr);
if ( (ua.getPort() <= 0) || (ua.getHost() == null) ) {
_log.info("Our direct SSU info is initialized, but not used in our address yet");
rv = true;
} else {
//_log.info("Our direct SSU info is initialized");
}
}
if (rv) {
if (_log.shouldLog(Log.INFO))
_log.info("Need to initialize our direct SSU info (" + Addresses.toString(externalListenHost, externalListenPort) + ')');
} else if (addr.getPort() <= 0 || addr.getHost() == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Our direct SSU info is initialized, but not used in our address yet");
rv = true;
} else {
//_log.info("Our direct SSU info is initialized");
}
return rv;
}
@ -1557,7 +1576,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public void stopListening() {
shutdown();
// will this work?
_externalAddress = null;
replaceAddress(null);
}
@ -1578,34 +1596,74 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return getCurrentAddresses();
}
private void rebuildExternalAddress() { rebuildExternalAddress(true); }
/**
* Update our IPv4 addresses AND tell the router to rebuild and republish the router info.
*
* @return the new address if changed, else null
*/
private RouterAddress rebuildExternalAddress() {
return rebuildExternalAddress(true);
}
private void rebuildExternalAddress(boolean allowRebuildRouterInfo) {
/**
* Update our IPv4 address and optionally tell the router to rebuild and republish the router info.
*
* @param allowRebuildRouterInfo whether to tell the router
* @return the new address if changed, else null
*/
private RouterAddress rebuildExternalAddress(boolean allowRebuildRouterInfo) {
// if the external port is specified, we want to use that to bind to even
// if we don't know the external host.
_externalListenPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
int port = _context.getProperty(PROP_EXTERNAL_PORT, -1);
byte[] ip = null;
if (explicitAddressSpecified()) {
try {
String host = _context.getProperty(PROP_EXTERNAL_HOST);
_externalListenHost = InetAddress.getByName(host);
} catch (UnknownHostException uhe) {
_externalListenHost = null;
}
String host = _context.getProperty(PROP_EXTERNAL_HOST);
return rebuildExternalAddress(host, port, allowRebuildRouterInfo);
}
return rebuildExternalAddress(ip, port, allowRebuildRouterInfo);
}
/**
* Update our IPv4 or IPv6 address and optionally tell the router to rebuild and republish the router info.
*
* @param ip new ip valid IPv4 or IPv6 or null
* @param port new valid port or -1
* @param allowRebuildRouterInfo whether to tell the router
* @return the new address if changed, else null
* @since IPv6
*/
private RouterAddress rebuildExternalAddress(byte[] ip, int port, boolean allowRebuildRouterInfo) {
if (ip == null || isValid(ip))
return rebuildExternalAddress(Addresses.toString(ip), port, allowRebuildRouterInfo);
return null;
}
/**
* Update our IPv4 or IPv6 address and optionally tell the router to rebuild and republish the router info.
*
* @param host new valid IPv4 or IPv6 or DNS hostname or null
* @param port new valid port or -1
* @param allowRebuildRouterInfo whether to tell the router
* @return the new address if changed, else null
* @since IPv6
*/
private RouterAddress rebuildExternalAddress(String host, int port, boolean allowRebuildRouterInfo) {
if (_context.router().isHidden())
return;
return null;
Properties options = new Properties();
OrderedProperties options = new OrderedProperties();
boolean directIncluded = false;
if ( allowDirectUDP() && (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) {
options.setProperty(UDPAddress.PROP_PORT, String.valueOf(_externalListenPort));
options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress());
// DNS name assumed IPv4
boolean isIPv6 = host != null && host.contains(":");
if (allowDirectUDP() && port > 0 && host != null) {
options.setProperty(UDPAddress.PROP_PORT, String.valueOf(port));
options.setProperty(UDPAddress.PROP_HOST, host);
directIncluded = true;
}
boolean introducersRequired = introducersRequired();
boolean introducersRequired = (!isIPv6) && introducersRequired();
boolean introducersIncluded = false;
if (introducersRequired || !directIncluded) {
int found = _introManager.pickInbound(options, PUBLIC_RELAY_COUNT);
@ -1638,40 +1696,42 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (_introKey != null)
options.setProperty(UDPAddress.PROP_INTRO_KEY, _introKey.toBase64());
RouterAddress addr = new RouterAddress();
// SSU seems to regulate at about 85%, so make it a little higher.
// If this is too low, both NTCP and SSU always have incremented cost and
// the whole mechanism is not helpful.
int cost = DEFAULT_COST;
if (ADJUST_COST && !haveCapacity(91))
addr.setCost(DEFAULT_COST + 1);
else
addr.setCost(DEFAULT_COST);
//addr.setExpiration(null);
addr.setTransportStyle(STYLE);
addr.setOptions(options);
cost++;
RouterAddress addr = new RouterAddress(STYLE, options, cost);
boolean wantsRebuild = false;
if ( (_externalAddress == null) || !(_externalAddress.equals(addr)) )
wantsRebuild = true;
RouterAddress current = getCurrentAddress(isIPv6);
boolean wantsRebuild = !addr.deepEquals(current);
RouterAddress oldAddress = _externalAddress;
_externalAddress = addr;
if (_log.shouldLog(Log.INFO))
_log.info("Address rebuilt: " + addr);
replaceAddress(addr, oldAddress);
if (allowRebuildRouterInfo && wantsRebuild)
_context.router().rebuildRouterInfo();
_needsRebuild = false;
if (wantsRebuild) {
if (_log.shouldLog(Log.INFO))
_log.info("Address rebuilt: " + addr);
replaceAddress(addr);
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
} else {
addr = null;
}
if (!isIPv6)
_needsRebuild = false;
return addr;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Wanted to rebuild my SSU address, but couldn't specify either the direct or indirect info (needs introducers? "
+ introducersRequired + ")", new Exception("source"));
_needsRebuild = true;
return null;
}
}
/**
* Replace then tell NTCP that we changed.
* Replace then tell NTCP that we changed.
*
* @param address the new address or null to remove all
*/
@Override
protected void replaceAddress(RouterAddress address) {
@ -1679,6 +1739,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.commSystem().notifyReplaceAddress(address);
}
/**
* Calls replaceAddress(address), then shuts down the router if
* dynamic keys is enabled, which it never is, so all this is unused.
*
* @param address the new address or null to remove all
*/
/****
protected void replaceAddress(RouterAddress address, RouterAddress oldAddress) {
replaceAddress(address);
if (oldAddress != null) {
@ -1704,7 +1771,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
}
}
****/
/**
* Do we require introducers?
*/
public boolean introducersRequired() {
/******************
* Don't do this anymore, as we are removing the checkbox from the UI,
@ -2621,8 +2692,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
long pingCutoff = now - (2 * 60*60*1000);
long pingFirewallCutoff = now - PING_FIREWALL_CUTOFF;
boolean shouldPingFirewall = _reachabilityStatus != CommSystemFacade.STATUS_OK;
int currentListenPort = getIPv4ListenPort();
boolean pingOneOnly = shouldPingFirewall && _externalListenPort == currentListenPort;
int currentListenPort = getListenPort(false);
boolean pingOneOnly = shouldPingFirewall && getExternalPort(false) == currentListenPort;
boolean shortLoop = shouldPingFirewall;
_expireBuffer.clear();
_runCount++;