Search in sources :

Example 26 with ByteArray

use of net.i2p.data.ByteArray in project i2p.i2p by i2p.

the class EventPumper method processRead.

/**
 *  OP_READ will always be set before this is called.
 *  This method will disable the interest if no more reads remain because of inbound bandwidth throttling.
 *  High-frequency path in thread.
 */
private void processRead(SelectionKey key) {
    NTCPConnection con = (NTCPConnection) key.attachment();
    ByteBuffer buf = acquireBuf();
    try {
        int read = con.getChannel().read(buf);
        if (read < 0) {
            // _context.statManager().addRateData("ntcp.readEOF", 1);
            if (con.isInbound() && con.getMessagesReceived() <= 0) {
                InetAddress addr = con.getChannel().socket().getInetAddress();
                int count;
                if (addr != null) {
                    byte[] ip = addr.getAddress();
                    ByteArray ba = new ByteArray(ip);
                    count = _blockedIPs.increment(ba);
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("Blocking IP " + Addresses.toString(ip) + " with count " + count + ": " + con);
                } else {
                    count = 1;
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("EOF on inbound before receiving any: " + con);
                }
                _context.statManager().addRateData("ntcp.dropInboundNoMessage", count);
            } else {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("EOF on " + con);
            }
            con.close();
            releaseBuf(buf);
        } else if (read == 0) {
            // if (_log.shouldLog(Log.DEBUG))
            // _log.debug("nothing to read for " + con + ", but stay interested");
            // stay interested
            // key.interestOps(key.interestOps() | SelectionKey.OP_READ);
            releaseBuf(buf);
            // workaround for channel stuck returning 0 all the time, causing 100% CPU
            int consec = con.gotZeroRead();
            if (consec >= 5) {
                _context.statManager().addRateData("ntcp.zeroReadDrop", 1);
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Fail safe zero read close " + con);
                con.close();
            } else {
                _context.statManager().addRateData("ntcp.zeroRead", consec);
                if (_log.shouldLog(Log.INFO))
                    _log.info("nothing to read for " + con + ", but stay interested");
            }
        } else {
            // clear counter for workaround above
            con.clearZeroRead();
            // ZERO COPY. The buffer will be returned in Reader.processRead()
            buf.flip();
            // con, buf);
            FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(read, "NTCP read");
            if (req.getPendingRequested() > 0) {
                // rare since we generally don't throttle inbound
                key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
                // if (_log.shouldLog(Log.DEBUG))
                // _log.debug("bw throttled reading for " + con + ", so we don't want to read anymore");
                _context.statManager().addRateData("ntcp.queuedRecv", read);
                con.queuedRecv(buf, req);
            } else {
                // fully allocated
                // if (_log.shouldLog(Log.DEBUG))
                // _log.debug("not bw throttled reading for " + con);
                // stay interested
                // key.interestOps(key.interestOps() | SelectionKey.OP_READ);
                con.recv(buf);
                _context.statManager().addRateData("ntcp.read", read);
            }
        }
    } catch (CancelledKeyException cke) {
        releaseBuf(buf);
        if (_log.shouldLog(Log.WARN))
            _log.warn("error reading on " + con, cke);
        con.close();
        _context.statManager().addRateData("ntcp.readError", 1);
    } catch (IOException ioe) {
        // common, esp. at outbound connect time
        releaseBuf(buf);
        if (con.isInbound() && con.getMessagesReceived() <= 0) {
            InetAddress addr = con.getChannel().socket().getInetAddress();
            int count;
            if (addr != null) {
                byte[] ip = addr.getAddress();
                ByteArray ba = new ByteArray(ip);
                count = _blockedIPs.increment(ba);
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Blocking IP " + Addresses.toString(ip) + " with count " + count + ": " + con);
            } else {
                count = 1;
                if (_log.shouldLog(Log.WARN))
                    _log.warn("IOE on inbound before receiving any: " + con);
            }
            _context.statManager().addRateData("ntcp.dropInboundNoMessage", count);
        } else {
            if (_log.shouldLog(Log.INFO))
                _log.info("error reading on " + con, ioe);
        }
        if (con.isEstablished()) {
            _context.statManager().addRateData("ntcp.readError", 1);
        } else {
            // Usually "connection reset by peer", probably a conn limit rejection?
            // although it could be a read failure during the DH handshake
            // Same stat as in processConnect()
            _context.statManager().addRateData("ntcp.connectFailedTimeoutIOE", 1);
            RouterIdentity rem = con.getRemotePeer();
            if (rem != null && !con.isInbound())
                _transport.markUnreachable(rem.calculateHash());
        }
        con.close();
    } catch (NotYetConnectedException nyce) {
        releaseBuf(buf);
        // ???
        key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
        if (_log.shouldLog(Log.WARN))
            _log.warn("error reading on " + con, nyce);
    }
}
Also used : CancelledKeyException(java.nio.channels.CancelledKeyException) RouterIdentity(net.i2p.data.router.RouterIdentity) ByteArray(net.i2p.data.ByteArray) IOException(java.io.IOException) NotYetConnectedException(java.nio.channels.NotYetConnectedException) ByteBuffer(java.nio.ByteBuffer) InetAddress(java.net.InetAddress)

Example 27 with ByteArray

use of net.i2p.data.ByteArray in project i2p.i2p by i2p.

the class EventPumper method processAccept.

private void processAccept(SelectionKey key) {
    // if (_log.shouldLog(Log.DEBUG))
    // _log.debug("processing accept");
    ServerSocketChannel servChan = (ServerSocketChannel) key.attachment();
    try {
        SocketChannel chan = servChan.accept();
        // don't throw an NPE if the connect is gone again
        if (chan == null)
            return;
        chan.configureBlocking(false);
        if (!_transport.allowConnection()) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Receive session request but at connection limit: " + chan.socket().getInetAddress());
            try {
                chan.close();
            } catch (IOException ioe) {
            }
            return;
        }
        byte[] ip = chan.socket().getInetAddress().getAddress();
        if (_context.blocklist().isBlocklisted(ip)) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Receive session request from blocklisted IP: " + chan.socket().getInetAddress());
            // _context.statManager().addRateData("ntcp.connectBlocklisted", 1, 0);
            try {
                chan.close();
            } catch (IOException ioe) {
            }
            return;
        }
        ByteArray ba = new ByteArray(ip);
        int count = _blockedIPs.count(ba);
        if (count > 0) {
            count = _blockedIPs.increment(ba);
            if (_log.shouldLog(Log.WARN))
                _log.warn("Blocking accept of IP with count " + count + ": " + Addresses.toString(ip));
            _context.statManager().addRateData("ntcp.dropInboundNoMessage", count);
            try {
                chan.close();
            } catch (IOException ioe) {
            }
            return;
        }
        // BUGFIX for firewalls. --Sponge
        if (shouldSetKeepAlive(chan))
            chan.socket().setKeepAlive(true);
        SelectionKey ckey = chan.register(_selector, SelectionKey.OP_READ);
        new NTCPConnection(_context, _transport, chan, ckey);
    // if (_log.shouldLog(Log.DEBUG))
    // _log.debug("new NTCP connection established: " +con);
    } catch (IOException ioe) {
        _log.error("Error accepting", ioe);
    }
}
Also used : SocketChannel(java.nio.channels.SocketChannel) ServerSocketChannel(java.nio.channels.ServerSocketChannel) SelectionKey(java.nio.channels.SelectionKey) ByteArray(net.i2p.data.ByteArray) IOException(java.io.IOException) ServerSocketChannel(java.nio.channels.ServerSocketChannel)

Example 28 with ByteArray

use of net.i2p.data.ByteArray in project i2p.i2p by i2p.

the class FragmentHandler method verifyPreprocessed.

/**
 * Verify that the preprocessed data hasn't been modified by checking the
 * H(payload+IV)[0:3] vs preprocessed[16:19], where payload is the data
 * after the padding.  Remember, the preprocessed data is formatted as
 * { IV + H[0:3] + padding + {instructions, fragment}* }.  This function is
 * very wasteful of memory usage as it doesn't operate inline (since IV and
 * payload are mixed up).  Later it may be worthwhile to explore optimizing
 * this.
 */
private boolean verifyPreprocessed(byte[] preprocessed, int offset, int length) {
    // ByteCache/ByteArray corruption detection
    // byte[] orig = new byte[length];
    // System.arraycopy(preprocessed, 0, orig, 0, length);
    // try {
    // Thread.sleep(75);
    // } catch (InterruptedException ie) {}
    // now we need to verify that the message was received correctly
    int paddingEnd = HopProcessor.IV_LENGTH + 4;
    while (preprocessed[offset + paddingEnd] != (byte) 0x00) {
        paddingEnd++;
        if (offset + paddingEnd >= length) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("cannot verify, going past the end [off=" + offset + " len=" + length + " paddingEnd=" + paddingEnd + " data: " + Base64.encode(preprocessed, offset, length));
            return false;
        }
    }
    // skip the last
    paddingEnd++;
    // larger than necessary, but always sufficient
    ByteArray ba = _validateCache.acquire();
    byte[] preV = ba.getData();
    int validLength = length - offset - paddingEnd + HopProcessor.IV_LENGTH;
    System.arraycopy(preprocessed, offset + paddingEnd, preV, 0, validLength - HopProcessor.IV_LENGTH);
    System.arraycopy(preprocessed, 0, preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("endpoint IV: " + Base64.encode(preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH));
    byte[] v = SimpleByteCache.acquire(Hash.HASH_LENGTH);
    _context.sha().calculateHash(preV, 0, validLength, v, 0);
    _validateCache.release(ba);
    boolean eq = DataHelper.eq(v, 0, preprocessed, offset + HopProcessor.IV_LENGTH, 4);
    if (!eq) {
        if (_log.shouldLog(Log.WARN)) {
            _log.warn("Corrupt tunnel message - verification fails: " + Base64.encode(preprocessed, offset + HopProcessor.IV_LENGTH, 4) + " != " + Base64.encode(v, 0, 4));
            _log.warn("No matching endpoint: # pad bytes: " + (paddingEnd - (HopProcessor.IV_LENGTH + 4) - 1) + " offset=" + offset + " length=" + length + " paddingEnd=" + paddingEnd + ' ' + Base64.encode(preprocessed, offset, length), new Exception("trace"));
        }
    }
    SimpleByteCache.release(v);
    if (eq) {
        int excessPadding = paddingEnd - (HopProcessor.IV_LENGTH + 4 + 1);
        if (// suboptimal fragmentation
        excessPadding > 0)
            _context.statManager().addRateData("tunnel.smallFragments", excessPadding);
        else
            _context.statManager().addRateData("tunnel.fullFragments", 1);
    }
    return eq;
}
Also used : ByteArray(net.i2p.data.ByteArray) I2NPMessageException(net.i2p.data.i2np.I2NPMessageException)

Example 29 with ByteArray

use of net.i2p.data.ByteArray in project i2p.i2p by i2p.

the class FragmentHandler method receiveTunnelMessage.

/**
 * Receive the raw preprocessed message at the endpoint, parsing out each
 * of the fragments, using those to fill various FragmentedMessages, and
 * sending the resulting I2NPMessages where necessary.  The received
 * fragments are all verified.
 */
public void receiveTunnelMessage(byte[] preprocessed, int offset, int length) {
    boolean ok = verifyPreprocessed(preprocessed, offset, length);
    if (!ok) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Unable to verify preprocessed data (pre.length=" + preprocessed.length + " off=" + offset + " len=" + length);
        _cache.release(new ByteArray(preprocessed));
        _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
        return;
    }
    // skip the IV
    offset += HopProcessor.IV_LENGTH;
    // skip the hash segment
    offset += 4;
    int padding = 0;
    while (preprocessed[offset] != (byte) 0x00) {
        // skip the padding
        offset++;
        // AIOOBE http://forum.i2p/viewtopic.php?t=3187
        if (offset >= TrivialPreprocessor.PREPROCESSED_SIZE) {
            _cache.release(new ByteArray(preprocessed));
            _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
            return;
        }
        padding++;
    }
    // skip the final 0x00, terminating the padding
    offset++;
    if (_log.shouldLog(Log.DEBUG)) {
        _log.debug("Fragments begin at offset=" + offset + " padding=" + padding);
    // _log.debug("fragments: " + Base64.encode(preprocessed, offset, preprocessed.length-offset));
    }
    try {
        while (offset < length) {
            int off = receiveFragment(preprocessed, offset, length);
            if (off < 0) {
                _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
                return;
            }
            offset = off;
        }
    } catch (ArrayIndexOutOfBoundsException aioobe) {
        _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
    } catch (NullPointerException npe) {
        if (_log.shouldLog(Log.ERROR))
            _log.error("Corrupt fragment received: offset = " + offset, npe);
        _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
    } catch (RuntimeException e) {
        if (_log.shouldLog(Log.ERROR))
            _log.error("Corrupt fragment received: offset = " + offset, e);
        _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
    // java.lang.IllegalStateException: don't get the completed size when we're not complete - null fragment i=0 of 1
    // at net.i2p.router.tunnel.FragmentedMessage.getCompleteSize(FragmentedMessage.java:194)
    // at net.i2p.router.tunnel.FragmentedMessage.toByteArray(FragmentedMessage.java:223)
    // at net.i2p.router.tunnel.FragmentHandler.receiveComplete(FragmentHandler.java:380)
    // at net.i2p.router.tunnel.FragmentHandler.receiveSubsequentFragment(FragmentHandler.java:353)
    // at net.i2p.router.tunnel.FragmentHandler.receiveFragment(FragmentHandler.java:208)
    // at net.i2p.router.tunnel.FragmentHandler.receiveTunnelMessage(FragmentHandler.java:92)
    // ...
    // still trying to find root cause
    // let's limit the damage here and skip the:
    // .transport.udp.MessageReceiver: b0rked receiving a message.. wazza huzza hmm?
    // throw e;
    } finally {
        // each of the FragmentedMessages populated make a copy out of the
        // payload, which they release separately, so we can release
        // immediately
        // 
        // This is certainly interesting, to wrap the 1024-byte array in a new ByteArray
        // in order to put it in the pool, but it shouldn't cause any harm.
        _cache.release(new ByteArray(preprocessed));
    }
}
Also used : ByteArray(net.i2p.data.ByteArray)

Example 30 with ByteArray

use of net.i2p.data.ByteArray in project i2p.i2p by i2p.

the class FragmentedMessage method getCompleteSize.

public int getCompleteSize() {
    if (!_lastReceived)
        throw new IllegalStateException("don't get the completed size when we're not complete!");
    if (_releasedAfter > 0) {
        RuntimeException e = new RuntimeException("use after free in FragmentedMessage");
        _log.error("FM completeSize()", e);
        throw e;
    }
    int size = 0;
    for (int i = 0; i <= _highFragmentNum; i++) {
        ByteArray ba = _fragments[i];
        // NPE seen here, root cause unknown
        if (ba == null)
            throw new IllegalStateException("don't get the completed size when we're not complete! - null fragment i=" + i + " of " + _highFragmentNum);
        size += ba.getValid();
    }
    return size;
}
Also used : ByteArray(net.i2p.data.ByteArray)

Aggregations

ByteArray (net.i2p.data.ByteArray)53 Test (org.junit.Test)14 IOException (java.io.IOException)9 ArrayList (java.util.ArrayList)3 Destination (net.i2p.data.Destination)3 InterruptedIOException (java.io.InterruptedIOException)2 SessionKey (net.i2p.data.SessionKey)2 I2NPMessage (net.i2p.data.i2np.I2NPMessage)2 I2NPMessageException (net.i2p.data.i2np.I2NPMessageException)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 InetAddress (java.net.InetAddress)1 ByteBuffer (java.nio.ByteBuffer)1 CancelledKeyException (java.nio.channels.CancelledKeyException)1 NotYetConnectedException (java.nio.channels.NotYetConnectedException)1 SelectionKey (java.nio.channels.SelectionKey)1 ServerSocketChannel (java.nio.channels.ServerSocketChannel)1 SocketChannel (java.nio.channels.SocketChannel)1 MessageDigest (java.security.MessageDigest)1 LinkedBlockingQueue (java.util.concurrent.LinkedBlockingQueue)1 I2PException (net.i2p.I2PException)1