Search in sources :

Example 1 with ByteArray

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

the class MessageInputStream method read.

/**
 *  On a read timeout, this returns 0
 *  (doesn't throw SocketTimeoutException like Socket)
 *  (doesn't throw InterruptedIOException like our javadocs say)
 */
@Override
public int read(byte[] target, int offset, int length) throws IOException {
    int readTimeout = _readTimeout;
    long expiration;
    if (readTimeout > 0)
        expiration = readTimeout + System.currentTimeMillis();
    else
        expiration = -1;
    synchronized (_dataLock) {
        if (_locallyClosed)
            throw new IOException("Input stream closed");
        throwAnyError();
        for (int i = 0; i < length; i++) {
            if ((_readyDataBlocks.isEmpty()) && (i == 0)) {
                while (_readyDataBlocks.isEmpty()) {
                    if (_locallyClosed)
                        throw new IOException("Input stream closed");
                    if ((_notYetReadyBlocks.isEmpty()) && (_closeReceived)) {
                        if (_log.shouldLog(Log.INFO))
                            _log.info("read(...," + offset + ", " + length + ")[" + i + "] got EOF after " + _readTotal + " " + toString());
                        return -1;
                    } else {
                        if (readTimeout < 0) {
                            if (_log.shouldLog(Log.DEBUG))
                                _log.debug("read(...," + offset + ", " + length + ")[" + i + "] with no timeout: " + toString());
                            try {
                                _dataLock.wait();
                            } catch (InterruptedException ie) {
                                IOException ioe2 = new InterruptedIOException("Interrupted read");
                                ioe2.initCause(ie);
                                throw ioe2;
                            }
                            if (_log.shouldLog(Log.DEBUG))
                                _log.debug("read(...," + offset + ", " + length + ")[" + i + "] with no timeout complete: " + toString());
                            throwAnyError();
                        } else if (readTimeout > 0) {
                            if (_log.shouldLog(Log.DEBUG))
                                _log.debug("read(...," + offset + ", " + length + ")[" + i + "] with timeout: " + readTimeout + ": " + toString());
                            try {
                                _dataLock.wait(readTimeout);
                            } catch (InterruptedException ie) {
                                IOException ioe2 = new InterruptedIOException("Interrupted read");
                                ioe2.initCause(ie);
                                throw ioe2;
                            }
                            if (_log.shouldLog(Log.DEBUG))
                                _log.debug("read(...," + offset + ", " + length + ")[" + i + "] with timeout complete: " + readTimeout + ": " + toString());
                            throwAnyError();
                        } else {
                            // noop, don't block
                            if (_log.shouldLog(Log.DEBUG))
                                _log.debug("read(...," + offset + ", " + length + ")[" + i + "] with nonblocking setup: " + toString());
                            return i;
                        }
                        if (_readyDataBlocks.isEmpty()) {
                            if (readTimeout > 0) {
                                long remaining = expiration - System.currentTimeMillis();
                                if (remaining <= 0) {
                                    // We do neither.
                                    if (_log.shouldLog(Log.INFO))
                                        _log.info("read(...," + offset + ", " + length + ")[" + i + "] expired: " + toString());
                                    return i;
                                } else {
                                    readTimeout = (int) remaining;
                                }
                            }
                        }
                    }
                }
                // we looped a few times then got data, so this pass doesnt count
                i--;
            } else if (_readyDataBlocks.isEmpty()) {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("read(...," + offset + ", " + length + ")[" + i + "] no more ready blocks, returning");
                return i;
            } else {
                // either was already ready, or we wait()ed and it arrived
                ByteArray cur = _readyDataBlocks.get(0);
                byte rv = cur.getData()[cur.getOffset() + _readyDataBlockIndex];
                _readyDataBlockIndex++;
                if (cur.getValid() <= _readyDataBlockIndex) {
                    _readyDataBlockIndex = 0;
                    _readyDataBlocks.remove(0);
                }
                _readTotal++;
                // rv < 0 ? rv + 256 : rv
                target[offset + i] = rv;
                if ((_readyDataBlockIndex <= 3) || (_readyDataBlockIndex >= cur.getValid() - 5)) {
                    if (_log.shouldLog(Log.DEBUG))
                        _log.debug("read(...," + offset + ", " + length + ")[" + i + "] after ready data: readyDataBlockIndex=" + _readyDataBlockIndex + " readyBlocks=" + _readyDataBlocks.size() + " readTotal=" + _readTotal);
                }
            // if (removed)
            // _cache.release(cur);
            }
        }
    // for (int i = 0; i < length; i++) {
    }
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("read(byte[]," + offset + ',' + length + ") read fully; total read: " + _readTotal);
    return length;
}
Also used : InterruptedIOException(java.io.InterruptedIOException) ByteArray(net.i2p.data.ByteArray) IOException(java.io.IOException) InterruptedIOException(java.io.InterruptedIOException)

Example 2 with ByteArray

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

the class MessageInputStream method messageReceived.

/**
 * A new message has arrived - toss it on the appropriate queue (moving
 * previously pending messages to the ready queue if it fills the gap, etc).
 * This does no limiting of pending data - see canAccept() for limiting.
 *
 * Warning - returns true if locally closed.
 *
 * @param messageId ID of the message
 * @param payload message payload, may be null or have null or zero-length data
 * @return true if this is a new packet, false if it is a dup
 */
public boolean messageReceived(long messageId, ByteArray payload) {
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("received msg ID " + messageId + " with " + (payload != null ? payload.getValid() + " bytes" : "no payload"));
    synchronized (_dataLock) {
        if (messageId <= _highestReadyBlockId) {
            if (_log.shouldLog(Log.INFO))
                _log.info("ignoring dup message " + messageId);
            _dataLock.notifyAll();
            // already received
            return false;
        }
        if (messageId > _highestBlockId)
            _highestBlockId = messageId;
        if (_highestReadyBlockId + 1 == messageId) {
            if (!_locallyClosed && payload.getValid() > 0) {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("accepting bytes as ready: " + payload.getValid());
                _readyDataBlocks.add(payload);
            }
            _highestReadyBlockId = messageId;
            long cur = _highestReadyBlockId + 1;
            // now pull in any previously pending blocks
            ByteArray ba;
            while ((ba = _notYetReadyBlocks.remove(Long.valueOf(cur))) != null) {
                if (ba.getData() != null && ba.getValid() > 0) {
                    _readyDataBlocks.add(ba);
                }
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("making ready the block " + cur);
                cur++;
                _highestReadyBlockId++;
            }
        // FIXME Javadocs for setReadTimeout() say we will throw
        // an InterruptedIOException.
        // Java throws a SocketTimeoutException.
        // We do neither.
        } else {
            // _notYetReadyBlocks size is limited in canAccept()
            if (_locallyClosed) {
                if (_log.shouldInfo())
                    _log.info("Message received on closed stream: " + messageId);
                // dont need the payload, just the msgId in order
                _notYetReadyBlocks.put(Long.valueOf(messageId), DUMMY_BA);
            } else {
                if (_log.shouldInfo())
                    _log.info("Message is out of order: " + messageId);
                _notYetReadyBlocks.put(Long.valueOf(messageId), payload);
            }
        }
        _dataLock.notifyAll();
    }
    return true;
}
Also used : ByteArray(net.i2p.data.ByteArray)

Example 3 with ByteArray

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

the class MessageOutputStream method clearData.

private void clearData(boolean shouldFlush) {
    ByteArray ba = null;
    if (_log.shouldLog(Log.INFO) && _valid > 0)
        _log.info("clearData() valid = " + _valid);
    synchronized (_dataLock) {
        // flush any data, but don't wait for it
        if (_valid > 0 && shouldFlush)
            _dataReceiver.writeData(_buf, 0, _valid);
        _written += _valid;
        _valid = 0;
        if (_buf != null) {
            ba = new ByteArray(_buf);
            _buf = null;
            _valid = 0;
        }
        _dataLock.notifyAll();
    }
    if (ba != null) {
        _dataCache.release(ba);
    }
}
Also used : ByteArray(net.i2p.data.ByteArray)

Example 4 with ByteArray

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

the class MessageOutputStream method close.

/**
 *  This does a flush, and BLOCKS until
 *  the CLOSE packet is acked.
 */
@Override
public void close() throws IOException {
    if (!_closed.compareAndSet(false, true)) {
        synchronized (_dataLock) {
            _dataLock.notifyAll();
        }
        _log.logCloseLoop("MOS");
        return;
    }
    // setting _closed before flush() will force flush() to send a CLOSE packet
    _flusher.cancel();
    // In 0.8.1 we rewrote flush() to only wait for accept into the window,
    // not "completion" (i.e. ack from the far end).
    // Unfortunately, that broke close(), at least in i2ptunnel HTTPClient.
    // Symptom was premature close, i.e. incomplete pages and images.
    // Possible cause - I2PTunnelRunner code? or the code here that follows flush()?
    // It seems like we shouldn't have to wait for the far-end ACK for a close packet,
    // should we? To be researched further.
    // false -> wait for completion, not just accept.
    flush(false);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Output stream closed after writing " + _written);
    ByteArray ba = null;
    synchronized (_dataLock) {
        if (_buf != null) {
            ba = new ByteArray(_buf);
            _buf = null;
            _valid = 0;
        }
        _dataLock.notifyAll();
    }
    if (ba != null) {
        _dataCache.release(ba);
    }
}
Also used : ByteArray(net.i2p.data.ByteArray)

Example 5 with ByteArray

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

the class Packet method readPacket.

/**
 * Read the packet from the buffer (starting at the offset) and return
 * the number of bytes read.
 *
 * @param buffer packet buffer containing the data
 * @param offset index into the buffer to start readign
 * @param length how many bytes within the buffer past the offset are
 *               part of the packet?
 *
 * @throws IllegalArgumentException if the data is b0rked
 */
public void readPacket(byte[] buffer, int offset, int length) throws IllegalArgumentException {
    if (buffer.length - offset < length)
        throw new IllegalArgumentException("len=" + buffer.length + " off=" + offset + " length=" + length);
    if (// min header size
    length < 22)
        throw new IllegalArgumentException("Too small: len=" + buffer.length);
    int cur = offset;
    setSendStreamId(DataHelper.fromLong(buffer, cur, 4));
    cur += 4;
    setReceiveStreamId(DataHelper.fromLong(buffer, cur, 4));
    cur += 4;
    setSequenceNum(DataHelper.fromLong(buffer, cur, 4));
    cur += 4;
    setAckThrough(DataHelper.fromLong(buffer, cur, 4));
    cur += 4;
    int numNacks = buffer[cur] & 0xff;
    cur++;
    if (length < 22 + numNacks * 4)
        throw new IllegalArgumentException("Too small with " + numNacks + " nacks: " + length);
    if (numNacks > 0) {
        long[] nacks = new long[numNacks];
        for (int i = 0; i < numNacks; i++) {
            nacks[i] = DataHelper.fromLong(buffer, cur, 4);
            cur += 4;
        }
        setNacks(nacks);
    } else {
        setNacks(null);
    }
    setResendDelay(buffer[cur] & 0xff);
    cur++;
    setFlags((int) DataHelper.fromLong(buffer, cur, 2));
    cur += 2;
    int optionSize = (int) DataHelper.fromLong(buffer, cur, 2);
    cur += 2;
    if (length < 22 + numNacks * 4 + optionSize)
        throw new IllegalArgumentException("Too small with " + numNacks + " nacks and " + optionSize + " options: " + length);
    int payloadBegin = cur + optionSize;
    int payloadSize = length - payloadBegin;
    if ((payloadSize < 0) || (payloadSize > MAX_PAYLOAD_SIZE))
        throw new IllegalArgumentException("length: " + length + " offset: " + offset + " begin: " + payloadBegin);
    // skip ahead to the payload
    // _payload = new ByteArray(new byte[payloadSize]);
    _payload = new ByteArray(buffer, payloadBegin, payloadSize);
    // ok now lets go back and deal with the options
    if (isFlagSet(FLAG_DELAY_REQUESTED)) {
        setOptionalDelay((int) DataHelper.fromLong(buffer, cur, 2));
        cur += 2;
    }
    if (isFlagSet(FLAG_FROM_INCLUDED)) {
        ByteArrayInputStream bais = new ByteArrayInputStream(buffer, cur, length - cur);
        try {
            Destination optionFrom = Destination.create(bais);
            cur += optionFrom.size();
            _optionFrom = optionFrom;
        } catch (IOException ioe) {
            throw new IllegalArgumentException("Bad from field", ioe);
        } catch (DataFormatException dfe) {
            throw new IllegalArgumentException("Bad from field", dfe);
        }
    }
    if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED)) {
        setOptionalMaxSize((int) DataHelper.fromLong(buffer, cur, 2));
        cur += 2;
    }
    if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
        Signature optionSignature;
        Destination from = getOptionalFrom();
        if (from != null) {
            optionSignature = new Signature(from.getSigningPublicKey().getType());
        } else {
            // super cheat for now, look for correct type,
            // assume no more options. If we add to the options
            // we will have to ask the manager.
            // We will get this wrong for Ed25519, same length as P256...
            // See verifySignature() below where we will recast the signature to
            // the correct type if necessary
            int siglen = payloadBegin - cur;
            SigType type = null;
            for (SigType t : SigType.values()) {
                if (t.getSigLen() == siglen) {
                    type = t;
                    break;
                }
            }
            if (type == null) {
                if (siglen < Signature.SIGNATURE_BYTES)
                    throw new IllegalArgumentException("unknown sig type len=" + siglen);
                // Hope it's the default type with some unknown options following;
                // if not the sig will fail later
                type = SigType.DSA_SHA1;
                siglen = Signature.SIGNATURE_BYTES;
            }
            optionSignature = new Signature(type);
        }
        byte[] buf = new byte[optionSignature.length()];
        System.arraycopy(buffer, cur, buf, 0, buf.length);
        optionSignature.setData(buf);
        setOptionalSignature(optionSignature);
        cur += buf.length;
    }
}
Also used : Destination(net.i2p.data.Destination) DataFormatException(net.i2p.data.DataFormatException) ByteArrayInputStream(java.io.ByteArrayInputStream) Signature(net.i2p.data.Signature) ByteArray(net.i2p.data.ByteArray) IOException(java.io.IOException) SigType(net.i2p.crypto.SigType)

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