Search in sources :

Example 1 with OutNetMessage

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);
        }
    }
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) Hash(net.i2p.data.Hash)

Example 2 with OutNetMessage

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();
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) RouterIdentity(net.i2p.data.router.RouterIdentity) RouterInfo(net.i2p.data.router.RouterInfo) RouterAddress(net.i2p.data.router.RouterAddress)

Example 3 with OutNetMessage

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) RouterIdentity(net.i2p.data.router.RouterIdentity) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) ArrayList(java.util.ArrayList)

Example 4 with OutNetMessage

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();
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) RouterIdentity(net.i2p.data.router.RouterIdentity) ArrayList(java.util.ArrayList) RouterAddress(net.i2p.data.router.RouterAddress) Hash(net.i2p.data.Hash) OutNetMessage(net.i2p.router.OutNetMessage) SessionKey(net.i2p.data.SessionKey) InetAddress(java.net.InetAddress)

Example 5 with OutNetMessage

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();
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage)

Aggregations

OutNetMessage (net.i2p.router.OutNetMessage)36 ArrayList (java.util.ArrayList)9 Hash (net.i2p.data.Hash)9 RouterInfo (net.i2p.data.router.RouterInfo)9 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)5 List (java.util.List)4 RouterIdentity (net.i2p.data.router.RouterIdentity)4 I2NPMessage (net.i2p.data.i2np.I2NPMessage)3 RouterAddress (net.i2p.data.router.RouterAddress)3 MessageSelector (net.i2p.router.MessageSelector)3 IOException (java.io.IOException)2 TunnelGatewayMessage (net.i2p.data.i2np.TunnelGatewayMessage)2 Job (net.i2p.router.Job)2 TunnelInfo (net.i2p.router.TunnelInfo)2 TunnelManagerFacade (net.i2p.router.TunnelManagerFacade)2 InetAddress (java.net.InetAddress)1 ByteBuffer (java.nio.ByteBuffer)1 ServerSocketChannel (java.nio.channels.ServerSocketChannel)1 SocketChannel (java.nio.channels.SocketChannel)1 Map (java.util.Map)1