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;
}
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;
}
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);
}
}
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);
}
}
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;
}
}
Aggregations