use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class EstablishmentManager method processExpired.
/**
* Caller should probably synch on outboundState
*/
private void processExpired(OutboundEstablishState outboundState) {
long nonce = outboundState.getIntroNonce();
if (nonce >= 0) {
// remove only if value == state
boolean removed = _liveIntroductions.remove(Long.valueOf(nonce), outboundState);
if (removed) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Send intro for " + outboundState + " timed out");
_context.statManager().addRateData("udp.sendIntroRelayTimeout", 1);
}
}
// only if == state
RemoteHostId claimed = outboundState.getClaimedAddress();
if (claimed != null)
_outboundByClaimedAddress.remove(claimed, outboundState);
_outboundByHash.remove(outboundState.getRemoteIdentity().calculateHash(), outboundState);
// should have already been removed in handleOutbound() above
// remove only if value == state
_outboundStates.remove(outboundState.getRemoteHostId(), outboundState);
if (outboundState.getState() != OB_STATE_CONFIRMED_COMPLETELY) {
if (_log.shouldLog(Log.INFO))
_log.info("Expired: " + outboundState + " Lifetime: " + outboundState.getLifetime());
OutNetMessage msg;
while ((msg = outboundState.getNextQueuedMessage()) != null) {
_transport.failed(msg, "Expired during failed establish");
}
String err = "Took too long to establish OB connection, state = " + outboundState.getState();
Hash peer = outboundState.getRemoteIdentity().calculateHash();
// _context.banlist().banlistRouter(peer, err, UDPTransport.STYLE);
_transport.markUnreachable(peer);
_transport.dropPeer(peer, false, err);
// _context.profileManager().commErrorOccurred(peer);
outboundState.fail();
} else {
OutNetMessage msg;
while ((msg = outboundState.getNextQueuedMessage()) != null) {
_transport.send(msg);
}
}
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class EstablishmentManager method handleCompletelyEstablished.
/**
* ok, fully received, add it to the established cons and queue up a
* netDb store to them
*/
private void handleCompletelyEstablished(InboundEstablishState state) {
if (state.isComplete())
return;
RouterIdentity remote = state.getConfirmedIdentity();
PeerState peer = new PeerState(_context, _transport, state.getSentIP(), state.getSentPort(), remote.calculateHash(), true);
peer.setCurrentCipherKey(state.getCipherKey());
peer.setCurrentMACKey(state.getMACKey());
peer.setWeRelayToThemAs(state.getSentRelayTag());
// Lookup the peer's MTU from the netdb, since it isn't included in the protocol setup (yet)
// TODO if we don't have RI then we will get it shortly, but too late.
// Perhaps netdb should notify transport when it gets a new RI...
RouterInfo info = _context.netDb().lookupRouterInfoLocally(remote.calculateHash());
if (info != null) {
RouterAddress addr = _transport.getTargetAddress(info);
if (addr != null) {
String smtu = addr.getOption(UDPAddress.PROP_MTU);
if (smtu != null) {
try {
boolean isIPv6 = state.getSentIP().length == 16;
int mtu = MTU.rectify(isIPv6, Integer.parseInt(smtu));
peer.setHisMTU(mtu);
} catch (NumberFormatException nfe) {
}
}
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle completely established (inbound): " + state + " - " + peer.getRemotePeer());
// if (true) // for now, only support direct
// peer.setRemoteRequiresIntroduction(false);
_transport.addRemotePeerState(peer);
boolean isIPv6 = state.getSentIP().length == 16;
_transport.inboundConnectionReceived(isIPv6);
_transport.setIP(remote.calculateHash(), state.getSentIP());
_context.statManager().addRateData("udp.inboundEstablishTime", state.getLifetime());
sendInboundComplete(peer);
OutNetMessage msg;
while ((msg = state.getNextQueuedMessage()) != null) {
if (_context.clock().now() - Router.CLOCK_FUDGE_FACTOR > msg.getExpiration()) {
msg.timestamp("took too long but established...");
_transport.failed(msg, "Took too long to establish, but it was established");
} else {
msg.timestamp("session fully established and sent");
_transport.send(msg);
}
}
state.complete();
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class EstablishmentManager method handleCompletelyEstablished.
/**
* ok, fully received, add it to the established cons and send any
* queued messages
*
* @return the new PeerState
*/
private PeerState handleCompletelyEstablished(OutboundEstablishState state) {
if (state.complete()) {
RouterIdentity rem = state.getRemoteIdentity();
if (rem != null)
return _transport.getPeerState(rem.getHash());
}
long now = _context.clock().now();
RouterIdentity remote = state.getRemoteIdentity();
// only if == state
RemoteHostId claimed = state.getClaimedAddress();
if (claimed != null)
_outboundByClaimedAddress.remove(claimed, state);
_outboundByHash.remove(remote.calculateHash(), state);
PeerState peer = new PeerState(_context, _transport, state.getSentIP(), state.getSentPort(), remote.calculateHash(), false);
peer.setCurrentCipherKey(state.getCipherKey());
peer.setCurrentMACKey(state.getMACKey());
peer.setTheyRelayToUsAs(state.getReceivedRelayTag());
int mtu = state.getRemoteAddress().getMTU();
if (mtu > 0)
peer.setHisMTU(mtu);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle completely established (outbound): " + state + " - " + peer.getRemotePeer());
_transport.addRemotePeerState(peer);
_transport.setIP(remote.calculateHash(), state.getSentIP());
_context.statManager().addRateData("udp.outboundEstablishTime", state.getLifetime());
DatabaseStoreMessage dbsm = null;
if (!state.isFirstMessageOurDSM()) {
dbsm = getOurInfo();
} else if (_log.shouldLog(Log.INFO)) {
_log.info("Skipping publish: " + state);
}
List<OutNetMessage> msgs = new ArrayList<OutNetMessage>(8);
OutNetMessage msg;
while ((msg = state.getNextQueuedMessage()) != null) {
if (now - Router.CLOCK_FUDGE_FACTOR > msg.getExpiration()) {
msg.timestamp("took too long but established...");
_transport.failed(msg, "Took too long to establish, but it was established");
} else {
msg.timestamp("session fully established and sent");
msgs.add(msg);
}
}
_transport.send(dbsm, msgs, peer);
return peer;
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class EstablishmentManager method establish.
/**
* @param queueIfMaxExceeded true normally, false if called from locked_admit so we don't loop
* @since 0.9.2
*/
private void establish(OutNetMessage msg, boolean queueIfMaxExceeded) {
RouterInfo toRouterInfo = msg.getTarget();
RouterAddress ra = _transport.getTargetAddress(toRouterInfo);
if (ra == null) {
_transport.failed(msg, "Remote peer has no address, cannot establish");
return;
}
RouterIdentity toIdentity = toRouterInfo.getIdentity();
Hash toHash = toIdentity.calculateHash();
if (toRouterInfo.getNetworkId() != _networkID) {
_context.banlist().banlistRouter(toHash);
_transport.markUnreachable(toHash);
_transport.failed(msg, "Remote peer is on the wrong network, cannot establish");
return;
}
UDPAddress addr = new UDPAddress(ra);
RemoteHostId maybeTo = null;
InetAddress remAddr = addr.getHostAddress();
int port = addr.getPort();
// claimed address (which we won't be using if indirect)
if (remAddr != null && port > 0 && port <= 65535) {
maybeTo = new RemoteHostId(remAddr.getAddress(), port);
if ((!_transport.isValid(maybeTo.getIP())) || (Arrays.equals(maybeTo.getIP(), _transport.getExternalIP()) && !_transport.allowLocal())) {
_transport.failed(msg, "Remote peer's IP isn't valid");
_transport.markUnreachable(toHash);
// _context.banlist().banlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address", UDPTransport.STYLE);
_context.statManager().addRateData("udp.establishBadIP", 1);
return;
}
InboundEstablishState inState = _inboundStates.get(maybeTo);
if (inState != null) {
// we have an inbound establishment in progress, queue it there instead
synchronized (inState) {
switch(inState.getState()) {
case IB_STATE_UNKNOWN:
case IB_STATE_REQUEST_RECEIVED:
case IB_STATE_CREATED_SENT:
case IB_STATE_CONFIRMED_PARTIALLY:
case IB_STATE_CONFIRMED_COMPLETELY:
// queue it
inState.addMessage(msg);
if (_log.shouldLog(Log.WARN))
_log.debug("OB msg queued to IES");
break;
case IB_STATE_COMPLETE:
// race, send it out (but don't call _transport.send() again and risk a loop)
_transport.sendIfEstablished(msg);
break;
case IB_STATE_FAILED:
// race, failed
_transport.failed(msg, "OB msg failed during IB establish");
break;
}
}
return;
}
}
RemoteHostId to;
boolean isIndirect = addr.getIntroducerCount() > 0 || maybeTo == null;
if (isIndirect) {
to = new RemoteHostId(toHash);
} else {
to = maybeTo;
}
OutboundEstablishState state = null;
int deferred = 0;
boolean rejected = false;
int queueCount = 0;
state = _outboundStates.get(to);
if (state == null) {
state = _outboundByHash.get(toHash);
if (state != null && _log.shouldLog(Log.INFO))
_log.info("Found by hash: " + state);
}
if (state == null) {
if (queueIfMaxExceeded && _outboundStates.size() >= getMaxConcurrentEstablish()) {
if (_queuedOutbound.size() >= MAX_QUEUED_OUTBOUND && !_queuedOutbound.containsKey(to)) {
rejected = true;
} else {
List<OutNetMessage> newQueued = new ArrayList<OutNetMessage>(MAX_QUEUED_PER_PEER);
List<OutNetMessage> queued = _queuedOutbound.putIfAbsent(to, newQueued);
if (queued == null) {
queued = newQueued;
if (_log.shouldLog(Log.WARN))
_log.warn("Queueing outbound establish to " + to + ", increase " + PROP_MAX_CONCURRENT_ESTABLISH);
}
// There are still races possible but this should prevent AIOOBE and NPE
synchronized (queued) {
queueCount = queued.size();
if (queueCount < MAX_QUEUED_PER_PEER) {
queued.add(msg);
// increment for the stat below
queueCount++;
} else {
rejected = true;
}
deferred = _queuedOutbound.size();
}
}
} else {
// must have a valid session key
byte[] keyBytes = addr.getIntroKey();
if (keyBytes == null) {
_transport.markUnreachable(toHash);
_transport.failed(msg, "Peer has no key, cannot establish");
return;
}
SessionKey sessionKey;
try {
sessionKey = new SessionKey(keyBytes);
} catch (IllegalArgumentException iae) {
_transport.markUnreachable(toHash);
_transport.failed(msg, "Peer has bad key, cannot establish");
return;
}
boolean allowExtendedOptions = VersionComparator.comp(toRouterInfo.getVersion(), VERSION_ALLOW_EXTENDED_OPTIONS) >= 0 && !_context.getBooleanProperty(PROP_DISABLE_EXT_OPTS);
// w/o ext options, it's always 'requested', no need to set
// don't ask if they are indirect
boolean requestIntroduction = allowExtendedOptions && !isIndirect && _transport.introducersMaybeRequired();
state = new OutboundEstablishState(_context, maybeTo, to, toIdentity, allowExtendedOptions, requestIntroduction, sessionKey, addr, _transport.getDHFactory());
OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state);
boolean isNew = oldState == null;
if (isNew) {
if (isIndirect && maybeTo != null)
_outboundByClaimedAddress.put(maybeTo, state);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Adding new " + state);
} else {
// whoops, somebody beat us to it, throw out the state we just created
state = oldState;
}
}
}
if (state != null) {
state.addMessage(msg);
List<OutNetMessage> queued = _queuedOutbound.remove(to);
if (queued != null) {
// see comments above
synchronized (queued) {
for (OutNetMessage m : queued) {
state.addMessage(m);
}
}
}
}
if (rejected) {
if (_log.shouldLog(Log.WARN))
_log.warn("Too many pending, rejecting outbound establish to " + to);
_transport.failed(msg, "Too many pending outbound connections");
_context.statManager().addRateData("udp.establishRejected", deferred);
return;
}
if (queueCount >= MAX_QUEUED_PER_PEER) {
_transport.failed(msg, "Too many pending messages for the given peer");
_context.statManager().addRateData("udp.establishOverflow", queueCount, deferred);
return;
}
if (deferred > 0)
msg.timestamp("too many deferred establishers");
else if (state != null)
msg.timestamp("establish state already waiting");
notifyActivity();
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class NTCPConnection method removeWriteBuf.
/**
* Remove the buffer, which _should_ be the one at the head of _writeBufs
*/
public void removeWriteBuf(ByteBuffer buf) {
_bytesSent += buf.capacity();
OutNetMessage msg = null;
boolean clearMessage = false;
if (_sendingMeta && (buf.capacity() == _meta.length)) {
_sendingMeta = false;
} else {
clearMessage = true;
}
_writeBufs.remove(buf);
if (clearMessage) {
// see synchronization comments in prepareNextWriteFast()
synchronized (_outbound) {
if (_currentOutbound != null) {
msg = _currentOutbound;
_currentOutbound = null;
}
}
if (msg != null) {
_lastSendTime = _context.clock().now();
_context.statManager().addRateData("ntcp.sendTime", msg.getSendTime());
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("I2NP message " + _messagesWritten + "/" + msg.getMessageId() + " sent after " + msg.getSendTime() + "/" + msg.getLifetime() + " with " + buf.capacity() + " bytes (uid=" + System.identityHashCode(msg) + " on " + toString() + ")");
}
_messagesWritten.incrementAndGet();
_transport.sendComplete(msg);
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("I2NP meta message sent completely");
}
if (// push through the bw limiter to reach _writeBufs
getOutboundQueueSize() > 0)
_transport.getWriter().wantsWrite(this, "write completed");
// this is not necessary, EventPumper.processWrite() handles this
// and it just causes unnecessary selector.wakeup() and looping
// boolean bufsRemain = !_writeBufs.isEmpty();
// if (bufsRemain) // send asap
// _transport.getPumper().wantsWrite(this);
updateStats();
}
Aggregations