2006-02-21 jrandom

* Throttle the outbound SSU establishment queue, so it doesn't fill up the
      heap when backlogged (and so that the messages queued up on it don't sit
      there forever)
    * Further SSU memory cleanup
    * Clean up the address regeneration code so it knows when to rebuild the
      local info more precisely.
This commit is contained in:
jrandom
2006-02-21 13:31:18 +00:00
committed by zzz
parent 9990126e3e
commit b4c495531a
14 changed files with 242 additions and 121 deletions

View File

@ -372,8 +372,6 @@ public class MessageOutputStream extends OutputStream {
/**
* called whenever the engine wants to push more data to the
* peer
*
* @return true if the data was flushed
*/
void flushAvailable(DataReceiver target) throws IOException {
flushAvailable(target, true);

View File

@ -102,7 +102,8 @@ public class PacketHandler {
Connection con = (sendId > 0 ? _manager.getConnectionByInboundId(sendId) : null);
if (con != null) {
receiveKnownCon(con, packet);
displayPacket(packet, "RECV", "wsize " + con.getOptions().getWindowSize() + " rto " + con.getOptions().getRTO());
if (_log.shouldLog(Log.INFO))
displayPacket(packet, "RECV", "wsize " + con.getOptions().getWindowSize() + " rto " + con.getOptions().getRTO());
} else {
receiveUnknownCon(packet, sendId);
displayPacket(packet, "UNKN", null);

View File

@ -153,7 +153,6 @@ public class AESEngine {
/** decrypt the data with the session key provided
* @param payload encrypted data
* @param sessionKey private session key
* @return unencrypted data
*/
public void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) {
System.arraycopy(payload, inIndex, rv, outIndex, rv.length - outIndex);

View File

@ -139,7 +139,6 @@ public class CryptixAESEngine extends AESEngine {
/** decrypt the data with the session key provided
* @param payload encrypted data
* @param sessionKey private session key
* @return unencrypted data
*/
public final void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) {
if ( (payload == null) || (rv == null) )

View File

@ -58,8 +58,8 @@ public class SimpleTimer {
*/
public void addEvent(TimedEvent event, long timeoutMs) { addEvent(event, timeoutMs, true); }
/**
* @param useEarliestEventTime if its already scheduled, use the earlier of the
* two timeouts, else use the later
* @param useEarliestTime if its already scheduled, use the earlier of the
* two timeouts, else use the later
*/
public void addEvent(TimedEvent event, long timeoutMs, boolean useEarliestTime) {
int totalEvents = 0;

View File

@ -1,10 +1,12 @@
$Id: history.txt,v 1.411 2006/02/20 13:12:47 jrandom Exp $
$Id: history.txt,v 1.412 2006/02/20 21:02:49 jrandom Exp $
2006-02-20 jrandom
2006-02-21 jrandom
* Throttle the outbound SSU establishment queue, so it doesn't fill up the
heap when backlogged (and so that the messages queued up on it don't sit
there forever)
* Further SSU memory cleanup
* Clean up the address regeneration code so it knows when to rebuild the
local info more precisely.
2006-02-20 jrandom
* Properly enable TCP this time (oops)

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
public final static String ID = "$Revision: 1.353 $ $Date: 2006/02/20 13:12:48 $";
public final static String ID = "$Revision: 1.354 $ $Date: 2006/02/20 21:02:49 $";
public final static String VERSION = "0.6.1.10";
public final static long BUILD = 9;
public final static long BUILD = 10;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -211,6 +211,7 @@ public class StatisticsManager implements Service {
Rate curRate = rate.getRate(periods[i]);
if (curRate == null) continue;
if (curRate.getLifetimeEventCount() <= 0) continue;
stats.setProperty("stat_" + rateName + '.' + getPeriod(curRate), renderRate(curRate, fudgeQuantity));
}
}

View File

@ -174,6 +174,7 @@ public class InboundMessageFragments /*implements UDPTransport.PartialACKSource
if (!fragmentOK)
break;
}
from.expireInboundMessages();
return fragments;
}

View File

@ -2,7 +2,10 @@ package net.i2p.router.transport.udp;
import java.util.*;
import net.i2p.data.Base64;
import net.i2p.data.SessionKey;
import net.i2p.data.RouterInfo;
import net.i2p.data.RouterAddress;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
@ -68,18 +71,47 @@ public class IntroductionManager {
return (PeerState)_outbound.get(new Long(id));
}
public void pickInbound(List rv, int howMany) {
/**
* Grab a bunch of peers who are willing to be introducers for us that
* are locally known (duh) and have published their own SSU address (duh^2).
* The picked peers have their info tacked on to the ssuOptions parameter for
* use in the SSU RouterAddress.
*
*/
public int pickInbound(Properties ssuOptions, int howMany) {
List peers = null;
int start = _context.random().nextInt(Integer.MAX_VALUE);
synchronized (_inbound) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Picking inbound out of " + _inbound);
if (_inbound.size() <= 0) return;
start = start % _inbound.size();
for (int i = 0; i < _inbound.size() && rv.size() < howMany; i++) {
PeerState cur = (PeerState)_inbound.get((start + i) % _inbound.size());
rv.add(cur);
}
if (_inbound.size() <= 0) return 0;
peers = new ArrayList(_inbound);
}
int sz = peers.size();
start = start % sz;
int found = 0;
for (int i = 0; i < sz && found < howMany; i++) {
PeerState cur = (PeerState)peers.get((start + i) % sz);
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(cur.getRemotePeer());
if (ri == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Picked peer has no local routerInfo: " + cur);
continue;
}
RouterAddress ra = ri.getTargetAddress(UDPTransport.STYLE);
if (ra == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Picked peer has no SSU address: " + ri);
continue;
}
UDPAddress ura = new UDPAddress(ra);
ssuOptions.setProperty(UDPAddress.PROP_INTRO_HOST_PREFIX + found, cur.getRemoteHostId().toHostString());
ssuOptions.setProperty(UDPAddress.PROP_INTRO_PORT_PREFIX + found, String.valueOf(cur.getRemotePort()));
ssuOptions.setProperty(UDPAddress.PROP_INTRO_KEY_PREFIX + found, Base64.encode(ura.getIntroKey()));
ssuOptions.setProperty(UDPAddress.PROP_INTRO_TAG_PREFIX + found, String.valueOf(cur.getTheyRelayToUsAs()));
found++;
}
return found;
}
public void receiveRelayIntro(RemoteHostId bob, UDPPacketReader reader) {

View File

@ -142,6 +142,11 @@ public class OutboundMessageFragments {
boolean ok = state.initialize(msg, msgBody);
if (ok) {
PeerState peer = _transport.getPeerState(target.getIdentity().calculateHash());
if (peer == null) {
_transport.failed(msg, "Peer disconnected quickly");
state.releaseResources();
return;
}
int active = peer.add(state);
synchronized (_activePeers) {
if (!_activePeers.contains(peer)) {

View File

@ -61,7 +61,8 @@ public class PacketHandler {
_context.statManager().createRateStat("udp.droppedInvalidInboundEstablish", "How old the packet we dropped due to invalidity (inbound establishment, bad key) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.droppedInvalidSkew", "How skewed the packet we dropped due to invalidity (valid except bad skew) was", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.packetDequeueTime", "How long it takes the UDPReader to pull a packet off the inbound packet queue (when its slow)", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.packetVerifyTime", "How long it takes the PacketHandler to verify a data packet after dequeueing (when its slow)", "udp", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.packetVerifyTime", "How long it takes the PacketHandler to verify a data packet after dequeueing (period is dequeue time)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("udp.packetVerifyTimeSlow", "How long it takes the PacketHandler to verify a data packet after dequeueing when its slow (period is dequeue time)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
}
public void startup() {
@ -140,8 +141,11 @@ public class PacketHandler {
timeToVerify = beforeRecv - packet.getTimeSinceReceived();
if (timeToDequeue > 50)
_context.statManager().addRateData("udp.packetDequeueTime", timeToDequeue, timeToDequeue);
if (timeToVerify > 50)
_context.statManager().addRateData("udp.packetVerifyTime", timeToVerify, timeToVerify);
if (timeToVerify > 0) {
_context.statManager().addRateData("udp.packetVerifyTime", timeToVerify, timeToDequeue);
if (timeToVerify > 100)
_context.statManager().addRateData("udp.packetVerifyTimeSlow", timeToVerify, timeToDequeue);
}
// back to the cache with thee!
packet.release();

View File

@ -606,7 +606,7 @@ public class PeerState {
int remaining = _inboundMessages.size();
for (Iterator iter = _inboundMessages.values().iterator(); remaining > 0; remaining--) {
InboundMessageState state = (InboundMessageState)iter.next();
if (state.isExpired()) {
if (state.isExpired() || _dead) {
iter.remove();
} else {
if (state.isComplete()) {
@ -977,6 +977,10 @@ public class PeerState {
public int add(OutboundMessageState state) {
if (_dead) {
_transport.failed(state, false);
return 0;
}
state.setPeer(this);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Adding to " + _remotePeer.toBase64() + ": " + state.getMessageId());
@ -989,20 +993,23 @@ public class PeerState {
}
/** drop all outbound messages */
public void dropOutbound() {
if (_dead) return;
//if (_dead) return;
_dead = true;
List msgs = _outboundMessages;
//_outboundMessages = null;
_retransmitter = null;
if (msgs != null) {
int sz = 0;
List tempList = null;
synchronized (msgs) {
tempList = new ArrayList(msgs);
msgs.clear();
sz = msgs.size();
if (sz > 0) {
tempList = new ArrayList(msgs);
msgs.clear();
}
}
int sz = tempList.size();
for (int i = 0; i < sz; i++)
_transport.failed((OutboundMessageState)tempList.get(i));
_transport.failed((OutboundMessageState)tempList.get(i), false);
}
}
@ -1025,7 +1032,10 @@ public class PeerState {
public int finishMessages() {
int rv = 0;
List msgs = _outboundMessages;
if (_dead) return 0;
if (_dead) {
dropOutbound();
return 0;
}
List succeeded = null;
List failed = null;
synchronized (msgs) {
@ -1404,14 +1414,18 @@ public class PeerState {
tmp.addAll(oldPeer._currentACKs);
oldPeer._currentACKs.clear();
}
synchronized (_currentACKs) { _currentACKs.addAll(tmp); }
if (!_dead) {
synchronized (_currentACKs) { _currentACKs.addAll(tmp); }
}
tmp.clear();
synchronized (oldPeer._currentACKsResend) {
tmp.addAll(oldPeer._currentACKsResend);
oldPeer._currentACKsResend.clear();
}
synchronized (_currentACKsResend) { _currentACKsResend.addAll(tmp); }
if (!_dead) {
synchronized (_currentACKsResend) { _currentACKsResend.addAll(tmp); }
}
tmp.clear();
Map msgs = new HashMap();
@ -1419,7 +1433,9 @@ public class PeerState {
msgs.putAll(oldPeer._inboundMessages);
oldPeer._inboundMessages.clear();
}
synchronized (_inboundMessages) { _inboundMessages.putAll(msgs); }
if (!_dead) {
synchronized (_inboundMessages) { _inboundMessages.putAll(msgs); }
}
msgs.clear();
OutboundMessageState retransmitter = null;
@ -1429,9 +1445,11 @@ public class PeerState {
retransmitter = oldPeer._retransmitter;
oldPeer._retransmitter = null;
}
synchronized (_outboundMessages) {
_outboundMessages.addAll(tmp);
_retransmitter = retransmitter;
if (!_dead) {
synchronized (_outboundMessages) {
_outboundMessages.addAll(tmp);
_retransmitter = retransmitter;
}
}
tmp.clear();
}

View File

@ -59,6 +59,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private long _introducersSelectedOn;
private long _lastInboundReceivedOn;
/** 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 */
@ -140,6 +143,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_introManager = new IntroductionManager(_context, this);
_introducersSelectedOn = -1;
_lastInboundReceivedOn = -1;
_needsRebuild = true;
_context.statManager().createRateStat("udp.alreadyConnected", "What is the lifetime of a reestablished session", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.droppedPeer", "How long ago did we receive from a dropped peer (duration == session lifetime", "udp", new long[] { 60*60*1000, 24*60*60*1000 });
@ -302,7 +306,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (_log.shouldLog(Log.INFO))
_log.info("External address received: " + RemoteHostId.toString(ourIP) + ":" + ourPort + " from "
+ from.toBase64() + ", isValid? " + isValid + ", explicitSpecified? " + explicitSpecified
+ ", receivedInboundRecent? " + inboundRecent);
+ ", receivedInboundRecent? " + inboundRecent + " status " + _reachabilityStatus);
if (explicitSpecified)
return;
@ -319,8 +323,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return;
} else if (inboundRecent) {
// use OS clock since its an ordering thing, not a time thing
if (_log.shouldLog(Log.WARN))
_log.warn("Ignoring IP address suggestion, since we have received an inbound con recently");
if (_log.shouldLog(Log.INFO))
_log.info("Ignoring IP address suggestion, since we have received an inbound con recently");
} else {
synchronized (this) {
if ( (_externalListenHost == null) ||
@ -328,6 +332,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) ||
(_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) {
// they told us something different and our tests are either old or failing
if (_log.shouldLog(Log.INFO))
_log.info("Trying to change our external address...");
try {
_externalListenHost = InetAddress.getByAddress(ourIP);
if (!fixedPort)
@ -337,14 +343,20 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
updated = true;
} catch (UnknownHostException uhe) {
_externalListenHost = null;
if (_log.shouldLog(Log.INFO))
_log.info("Error trying to change our external address", uhe);
}
} else {
// they told us something different, but our tests are recent and positive,
// so lets test again
fireTest = true;
if (_log.shouldLog(Log.INFO))
_log.info("Different address, but we're fine..");
}
} else {
// matched what we expect
if (_log.shouldLog(Log.INFO))
_log.info("Same address as the current one");
}
}
}
@ -524,8 +536,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (oldEstablishedOn > 0)
_context.statManager().addRateData("udp.alreadyConnected", oldEstablishedOn, 0);
// if we need introducers, try to shift 'em around every 10 minutes
if (introducersRequired() && (_introducersSelectedOn < _context.clock().now() - 10*60*1000))
if (needsRebuild())
rebuildExternalAddress();
if (getReachabilityStatus() != CommSystemFacade.STATUS_OK) {
@ -536,8 +547,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
public RouterAddress getCurrentAddress() {
// if we need introducers, try to shift 'em around every 10 minutes
if (introducersRequired() && (_introducersSelectedOn < _context.clock().now() - 10*60*1000))
if (needsRebuild())
rebuildExternalAddress(false);
return super.getCurrentAddress();
}
@ -578,8 +588,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Received another message: " + inMsg.getClass().getName());
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received another message: " + inMsg.getClass().getName());
}
PeerState peer = getPeerState(remoteIdentHash);
super.messageReceived(inMsg, remoteIdent, remoteIdentHash, msToReceive, bytesReceived);
@ -636,12 +646,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
peer.dropOutbound();
peer.expireInboundMessages();
_introManager.remove(peer);
_fragments.dropPeer(peer);
// a bit overzealous - perhaps we should only rebuild the external if the peer being dropped
// is one of our introducers? dropping it only if we are considered 'not reachable' is a start
if (introducersRequired())
rebuildExternalAddress();
PeerState altByIdent = null;
PeerState altByHost = null;
if (peer.getRemotePeer() != null) {
dropPeerCapacities(peer);
@ -655,14 +665,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.statManager().addRateData("udp.droppedPeerInactive", now - peer.getLastReceiveTime(), now - peer.getKeyEstablishedTime());
}
synchronized (_peersByIdent) {
_peersByIdent.remove(peer.getRemotePeer());
altByIdent = (PeerState)_peersByIdent.remove(peer.getRemotePeer());
}
}
RemoteHostId remoteId = peer.getRemoteHostId();
if (remoteId != null) {
synchronized (_peersByRemoteHost) {
_peersByRemoteHost.remove(remoteId);
altByHost = (PeerState)_peersByRemoteHost.remove(remoteId);
}
}
@ -672,6 +682,64 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (SHOULD_FLOOD_PEERS)
_flooder.removePeer(peer);
_expireEvent.remove(peer);
if (needsRebuild())
rebuildExternalAddress();
// deal with races to make sure we drop the peers fully
if ( (altByIdent != null) && (peer != altByIdent) ) dropPeer(altByIdent, shouldShitlist);
if ( (altByHost != null) && (peer != altByHost) ) dropPeer(altByHost, shouldShitlist);
}
private boolean needsRebuild() {
if (_needsRebuild) return true; // simple enough
if (_context.router().isHidden()) return false;
if (introducersRequired()) {
RouterAddress addr = _externalAddress;
UDPAddress ua = new UDPAddress(addr);
int valid = 0;
Hash peerHash = new Hash();
for (int i = 0; i < ua.getIntroducerCount(); i++) {
// warning: this is only valid as long as we use the ident hash as their key.
peerHash.setData(ua.getIntroducerKey(i));
PeerState peer = getPeerState(peerHash);
if (peer != null)
valid++;
}
if (valid >= PUBLIC_RELAY_COUNT) {
// try to shift 'em around every 10 minutes or so
if (_introducersSelectedOn < _context.clock().now() - 10*60*1000) {
if (_log.shouldLog(Log.WARN))
_log.warn("Our introducers are valid, but thy havent changed in a while, so lets rechoose");
return true;
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Our introducers are valid and haven't changed in a while");
return false;
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Our introducers are not valid (" +valid + ")");
return true;
}
} else {
boolean rv = (_externalListenHost == null) || (_externalListenPort <= 0);
if (_log.shouldLog(Log.INFO)) {
if (rv) {
_log.info("Need to initialize our direct SSU info");
} 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");
}
}
}
return rv;
}
}
/**
@ -785,20 +853,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (ok)
_fragments.add(state);
}
//public OutNetMessage getNextMessage() { return getNextMessage(-1); }
/**
* Get the next message, blocking until one is found or the expiration
* reached.
*
* @param blockUntil expiration, or -1 if indefinite
*/
/*
public OutNetMessage getNextMessage(long blockUntil) {
return _outboundMessages.getNext(blockUntil);
}
*/
// we don't need the following, since we have our own queueing
protected void outboundMessageReady() { throw new UnsupportedOperationException("Not used for UDP"); }
@ -848,68 +902,58 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
Properties options = new Properties();
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());
directIncluded = true;
}
boolean introducersRequired = introducersRequired();
if (introducersRequired) {
List peers = new ArrayList(PUBLIC_RELAY_COUNT);
int found = 0;
_introManager.pickInbound(peers, PUBLIC_RELAY_COUNT);
if (_log.shouldLog(Log.INFO))
_log.info("Introducers required, picked peers: " + peers);
for (int i = 0; i < peers.size(); i++) {
PeerState peer = (PeerState)peers.get(i);
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer());
if (ri == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Picked peer has no local routerInfo: " + peer);
continue;
}
RouterAddress ra = ri.getTargetAddress(STYLE);
if (ra == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Picked peer has no SSU address: " + ri);
continue;
}
UDPAddress ura = new UDPAddress(ra);
options.setProperty(UDPAddress.PROP_INTRO_HOST_PREFIX + i, peer.getRemoteHostId().toHostString());
options.setProperty(UDPAddress.PROP_INTRO_PORT_PREFIX + i, String.valueOf(peer.getRemotePort()));
options.setProperty(UDPAddress.PROP_INTRO_KEY_PREFIX + i, Base64.encode(ura.getIntroKey()));
options.setProperty(UDPAddress.PROP_INTRO_TAG_PREFIX + i, String.valueOf(peer.getTheyRelayToUsAs()));
found++;
}
boolean introducersIncluded = false;
if (introducersRequired || !directIncluded) {
int found = _introManager.pickInbound(options, PUBLIC_RELAY_COUNT);
if (found > 0) {
if (_log.shouldLog(Log.INFO))
_log.info("Picked peers: " + found);
_introducersSelectedOn = _context.clock().now();
introducersIncluded = true;
}
}
if ( allowDirectUDP() && (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) {
options.setProperty(UDPAddress.PROP_PORT, String.valueOf(_externalListenPort));
options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress());
// if we have explicit external addresses, they had better be reachable
if (introducersRequired)
options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING);
else
options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER);
}
options.setProperty(UDPAddress.PROP_INTRO_KEY, _introKey.toBase64());
RouterAddress addr = new RouterAddress();
addr.setCost(5);
addr.setExpiration(null);
addr.setTransportStyle(STYLE);
addr.setOptions(options);
boolean wantsRebuild = false;
if ( (_externalAddress == null) || !(_externalAddress.equals(addr)) )
wantsRebuild = true;
RouterAddress oldAddress = _externalAddress;
_externalAddress = addr;
if (_log.shouldLog(Log.INFO))
_log.info("Address rebuilt: " + addr);
replaceAddress(addr, oldAddress);
if (allowRebuildRouterInfo)
_context.router().rebuildRouterInfo();
// if we have explicit external addresses, they had better be reachable
if (introducersRequired)
options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING);
else
options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER);
if (directIncluded || introducersIncluded) {
options.setProperty(UDPAddress.PROP_INTRO_KEY, _introKey.toBase64());
RouterAddress addr = new RouterAddress();
addr.setCost(5);
addr.setExpiration(null);
addr.setTransportStyle(STYLE);
addr.setOptions(options);
boolean wantsRebuild = false;
if ( (_externalAddress == null) || !(_externalAddress.equals(addr)) )
wantsRebuild = true;
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;
} 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;
}
}
protected void replaceAddress(RouterAddress address, RouterAddress oldAddress) {
@ -940,13 +984,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public boolean introducersRequired() {
String forceIntroducers = _context.getProperty(PROP_FORCE_INTRODUCERS);
if ( (forceIntroducers != null) && (Boolean.valueOf(forceIntroducers).booleanValue()) )
if ( (forceIntroducers != null) && (Boolean.valueOf(forceIntroducers).booleanValue()) ) {
if (_log.shouldLog(Log.INFO))
_log.info("Force introducers specified");
return true;
switch (getReachabilityStatus()) {
}
short status = getReachabilityStatus();
switch (status) {
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
case CommSystemFacade.STATUS_DIFFERENT:
if (_log.shouldLog(Log.INFO))
_log.info("Require introducers, because our status is " + status);
return true;
default:
if (!allowDirectUDP()) {
if (_log.shouldLog(Log.INFO))
_log.info("Require introducers, because we do not allow direct UDP connections");
return true;
}
return false;
}
}
@ -966,11 +1021,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private static final int DROP_INACTIVITY_TIME = 60*1000;
public void failed(OutboundMessageState msg) {
public void failed(OutboundMessageState msg) { failed(msg, true); }
void failed(OutboundMessageState msg, boolean allowPeerFailure) {
if (msg == null) return;
int consecutive = 0;
OutNetMessage m = msg.getMessage();
if ( (msg.getPeer() != null) &&
if ( allowPeerFailure && (msg.getPeer() != null) &&
( (msg.getMaxSends() >= OutboundMessageFragments.MAX_VOLLEYS) ||
(msg.isExpired())) ) {
//long recvDelay = _context.clock().now() - msg.getPeer().getLastReceiveTime();
@ -1456,6 +1512,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private static final long STATUS_GRACE_PERIOD = 5*60*1000;
void setReachabilityStatus(short status) {
short old = _reachabilityStatus;
long now = _context.clock().now();
switch (status) {
case CommSystemFacade.STATUS_OK:
@ -1485,6 +1542,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
//}
break;
}
if ( (status != old) && (status != CommSystemFacade.STATUS_UNKNOWN) ) {
if (needsRebuild())
rebuildExternalAddress();
}
}
private static final String PROP_REACHABILITY_STATUS_OVERRIDE = "i2np.udp.status";
public short getReachabilityStatus() {