use of net.i2p.data.ByteArray in project i2p.i2p by i2p.
the class ConnectionDataReceiver method buildPacket.
/**
* Compose a packet.
* Most flags are set here; however, some are set in Connection.sendPacket()
* and Connection.ResendPacketEvent.retransmit().
* Take care not to set the same options both here and in Connection.
*
* @param buf data to be sent - may be null
* @param off offset into the buffer to start writing from
* @param size how many bytes of the buffer to write (may be 0)
* @param forceIncrement even if the buffer is empty, increment the packetId
* so we get an ACK back
* @return the packet to be sent
*/
private PacketLocal buildPacket(byte[] buf, int off, int size, boolean forceIncrement) {
if (size > Packet.MAX_PAYLOAD_SIZE)
throw new IllegalArgumentException("size is too large (" + size + ")");
boolean ackOnly = isAckOnly(_connection, size);
boolean isFirst = (_connection.getAckedPackets() <= 0) && (_connection.getUnackedPacketsSent() <= 0);
PacketLocal packet = new PacketLocal(_context, _connection.getRemotePeer(), _connection);
// ByteArray data = packet.acquirePayload();
ByteArray data = new ByteArray(new byte[size]);
if (size > 0)
System.arraycopy(buf, off, data.getData(), 0, size);
data.setValid(size);
data.setOffset(0);
packet.setPayload(data);
if ((ackOnly && !forceIncrement) && (!isFirst))
packet.setSequenceNum(0);
else
packet.setSequenceNum(_connection.getNextOutboundPacketNum());
packet.setSendStreamId(_connection.getSendStreamId());
packet.setReceiveStreamId(_connection.getReceiveStreamId());
// not needed here, handled in PacketQueue.enqueue()
// con.getInputStream().updateAcks(packet);
// Do not set optional delay here, set in Connection.sendPacket()
// bugfix release 0.7.8, we weren't dividing by 1000
packet.setResendDelay(_connection.getOptions().getResendDelay() / 1000);
if (_connection.getOptions().getProfile() == ConnectionOptions.PROFILE_INTERACTIVE)
packet.setFlag(Packet.FLAG_PROFILE_INTERACTIVE, true);
else
packet.setFlag(Packet.FLAG_PROFILE_INTERACTIVE, false);
// if ( (!ackOnly) && (packet.getSequenceNum() <= 0) ) {
if (isFirst) {
packet.setFlag(Packet.FLAG_SYNCHRONIZE);
packet.setOptionalFrom();
packet.setOptionalMaxSize(_connection.getOptions().getMaxMessageSize());
}
packet.setLocalPort(_connection.getLocalPort());
packet.setRemotePort(_connection.getPort());
if (_connection.getSendStreamId() == Packet.STREAM_ID_UNKNOWN) {
packet.setFlag(Packet.FLAG_NO_ACK);
}
//
if (_connection.getOutputStream().getClosed() && ((size > 0) || (_connection.getUnackedPacketsSent() <= 0) || (packet.getSequenceNum() > 0))) {
packet.setFlag(Packet.FLAG_CLOSE);
_connection.notifyCloseSent();
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("New OB pkt (acks not yet filled in): " + packet + " on " + _connection);
return packet;
}
use of net.i2p.data.ByteArray in project i2p.i2p by i2p.
the class ConnectionManager method receiveConnection.
/**
* Create a new connection based on the SYN packet we received.
*
* @param synPacket SYN packet to process
* @return created Connection with the packet's data already delivered to
* it, or null if the syn's streamId was already taken
*/
public Connection receiveConnection(Packet synPacket) {
ConnectionOptions opts = new ConnectionOptions(_defaultOptions);
opts.setPort(synPacket.getRemotePort());
opts.setLocalPort(synPacket.getLocalPort());
boolean reject = false;
int active = 0;
int total = 0;
// }
if (locked_tooManyStreams()) {
if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN))
_log.logAlways(Log.WARN, "Refusing connection since we have exceeded our max of " + _defaultOptions.getMaxConns() + " connections");
reject = true;
} else {
// this may not be right if more than one is enabled
String why = shouldRejectConnection(synPacket);
if (why != null) {
if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN))
_log.logAlways(Log.WARN, "Refusing connection since peer is " + why + (synPacket.getOptionalFrom() == null ? "" : ": " + synPacket.getOptionalFrom().toBase32()));
reject = true;
}
}
_context.statManager().addRateData("stream.receiveActive", active, total);
if (reject) {
Destination from = synPacket.getOptionalFrom();
if (from == null)
return null;
String resp = _defaultOptions.getLimitAction();
if ("drop".equals(resp)) {
// always drop
return null;
}
Hash h = from.calculateHash();
if (_globalBlacklist.contains(h) || (_defaultOptions.isAccessListEnabled() && !_defaultOptions.getAccessList().contains(h)) || (_defaultOptions.isBlacklistEnabled() && _defaultOptions.getBlacklist().contains(h))) {
// always drop these regardless of setting
return null;
}
if ((_minuteThrottler != null && _minuteThrottler.isOverBy(h, DROP_OVER_LIMIT)) || (_hourThrottler != null && _hourThrottler.isOverBy(h, DROP_OVER_LIMIT)) || (_dayThrottler != null && _dayThrottler.isOverBy(h, DROP_OVER_LIMIT))) {
// thus more inbound, but let's not spend several KB on the outbound.
if (_log.shouldLog(Log.INFO))
_log.info("Dropping limit response to " + from.toBase32());
return null;
}
boolean reset = resp == null || resp.equals("reset") || resp.length() <= 0;
boolean http = !reset && "http".equals(resp);
boolean custom = !(reset || http);
String sendResponse;
if (http) {
sendResponse = LIMIT_HTTP_RESPONSE;
} else if (custom) {
sendResponse = resp.replace("\\r", "\r").replace("\\n", "\n");
} else {
sendResponse = null;
}
PacketLocal reply = new PacketLocal(_context, from, synPacket.getSession());
if (sendResponse != null) {
reply.setFlag(Packet.FLAG_SYNCHRONIZE | Packet.FLAG_CLOSE | Packet.FLAG_SIGNATURE_INCLUDED);
reply.setSequenceNum(0);
ByteArray payload = new ByteArray(DataHelper.getUTF8(sendResponse));
reply.setPayload(payload);
} else {
reply.setFlag(Packet.FLAG_RESET | Packet.FLAG_SIGNATURE_INCLUDED);
}
reply.setAckThrough(synPacket.getSequenceNum());
reply.setSendStreamId(synPacket.getReceiveStreamId());
long rcvStreamId = assignRejectId();
reply.setReceiveStreamId(rcvStreamId);
reply.setOptionalFrom();
reply.setLocalPort(synPacket.getLocalPort());
reply.setRemotePort(synPacket.getRemotePort());
if (_log.shouldInfo())
// _log.info("Over limit, sending " + (sendResponse != null ? "configured response" : "reset") + " to " + from.toBase32());
_log.info("Over limit, sending " + reply + " to " + from.toBase32());
// this just sends the packet - no retries or whatnot
_outboundQueue.enqueue(reply);
return null;
}
Connection con = new Connection(_context, this, synPacket.getSession(), _schedulerChooser, _timer, _outboundQueue, _conPacketHandler, opts, true);
_tcbShare.updateOptsFromShare(con);
assignReceiveStreamId(con);
// finally, we know enough that we can log the packet with the conn filled in
if (I2PSocketManagerFull.pcapWriter != null && _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
synPacket.logTCPDump(con);
try {
// This validates the packet, and sets the con's SendStreamID and RemotePeer
con.getPacketHandler().receivePacket(synPacket, con);
} catch (I2PException ie) {
_connectionByInboundId.remove(Long.valueOf(con.getReceiveStreamId()));
return null;
}
_context.statManager().addRateData("stream.connectionReceived", 1);
return con;
}
use of net.i2p.data.ByteArray in project i2p.i2p by i2p.
the class ConnectionManager method receivePing.
/**
* Process a ping by checking for throttling, etc., then sending a pong.
*
* @param con null if unknown
* @param ping Ping packet to process, must have From and Sig fields,
* with signature already verified, only if answerPings() returned true
* @return true if we sent a pong
* @since 0.9.12 from PacketHandler.receivePing()
*/
public boolean receivePing(Connection con, Packet ping) {
Destination dest = ping.getOptionalFrom();
if (dest == null)
return false;
if (con == null) {
// Use the same throttling as for connections
String why = shouldRejectConnection(ping);
if (why != null) {
if ((!_defaultOptions.getDisableRejectLogging()) || _log.shouldLog(Log.WARN))
_log.logAlways(Log.WARN, "Dropping ping since peer is " + why + ": " + dest.calculateHash());
return false;
}
} else {
// in-connection ping to a 3rd party ???
if (!dest.equals(con.getRemotePeer())) {
_log.logAlways(Log.WARN, "Dropping ping from " + con.getRemotePeer().calculateHash() + " to " + dest.calculateHash());
return false;
}
}
PacketLocal pong = new PacketLocal(_context, dest, ping.getSession());
pong.setFlag(Packet.FLAG_ECHO | Packet.FLAG_NO_ACK);
pong.setReceiveStreamId(ping.getSendStreamId());
pong.setLocalPort(ping.getLocalPort());
pong.setRemotePort(ping.getRemotePort());
// as of 0.9.18, return the payload
ByteArray payload = ping.getPayload();
if (payload != null) {
if (payload.getValid() > MAX_PONG_PAYLOAD)
payload.setValid(MAX_PONG_PAYLOAD);
pong.setPayload(payload);
}
_outboundQueue.enqueue(pong);
return true;
}
use of net.i2p.data.ByteArray in project i2p.i2p by i2p.
the class HTTPResponseOutputStream method ensureCapacity.
/**
* grow (and free) the buffer as necessary
* @throws IOException if the headers are too big
*/
private void ensureCapacity() throws IOException {
if (_headerBuffer.getValid() >= MAX_HEADER_SIZE)
throw new IOException("Max header size exceeded: " + MAX_HEADER_SIZE);
if (_headerBuffer.getValid() + 1 >= _headerBuffer.getData().length) {
int newSize = (int) (_headerBuffer.getData().length * 1.5);
ByteArray newBuf = new ByteArray(new byte[newSize]);
System.arraycopy(_headerBuffer.getData(), 0, newBuf.getData(), 0, _headerBuffer.getValid());
newBuf.setValid(_headerBuffer.getValid());
newBuf.setOffset(0);
// if we changed the ByteArray size, don't put it back in the cache
if (_headerBuffer.getData().length == CACHE_SIZE)
_cache.release(_headerBuffer);
_headerBuffer = newBuf;
}
}
use of net.i2p.data.ByteArray in project i2p.i2p by i2p.
the class Message method sendMessage.
/**
* Utility method for sending a message through a DataStream.
*/
void sendMessage(DataOutputStream dos) throws IOException {
// KEEP_ALIVE is special.
if (type == KEEP_ALIVE) {
dos.writeInt(0);
return;
}
ByteArray ba;
// Get deferred data
if (data == null && dataLoader != null) {
ba = dataLoader.loadData(piece, begin, length);
if (ba == null)
// hmm will get retried, but shouldn't happen
return;
data = ba.getData();
} else {
ba = null;
}
// Calculate the total length in bytes
// Type is one byte.
int datalen = 1;
// piece is 4 bytes.
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL || type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
datalen += 4;
// begin/offset is 4 bytes
if (type == REQUEST || type == PIECE || type == CANCEL || type == REJECT)
datalen += 4;
// length is 4 bytes
if (type == REQUEST || type == CANCEL || type == REJECT)
datalen += 4;
else // msg type is 1 byte
if (type == EXTENSION)
datalen += 1;
else if (type == PORT)
datalen += 2;
// add length of data for piece or bitfield array.
if (type == BITFIELD || type == PIECE || type == EXTENSION)
datalen += len;
// Send length
dos.writeInt(datalen);
dos.writeByte(type & 0xFF);
// Send additional info (piece number)
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL || type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
dos.writeInt(piece);
// Send additional info (begin/offset)
if (type == REQUEST || type == PIECE || type == CANCEL || type == REJECT)
dos.writeInt(begin);
// Send additional info (length); for PIECE this is implicit.
if (type == REQUEST || type == CANCEL || type == REJECT)
dos.writeInt(length);
else if (type == EXTENSION)
dos.writeByte((byte) piece & 0xff);
else if (type == PORT)
dos.writeShort(piece & 0xffff);
// Send actual data
if (type == BITFIELD || type == PIECE || type == EXTENSION)
dos.write(data, off, len);
// Was pulled from cache in Storage.getPiece() via dataLoader
if (ba != null && ba.getData().length == BUFSIZE)
_cache.release(ba, false);
}
Aggregations