forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.zzz.test2' (head 9dca19f228a66b5ac646c3d97d4f018c733081de)
to branch 'i2p.i2p' (head e7f2b0990f1ff9ab0e0d8633ac2faf35a993b917)
This commit is contained in:
@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 10;
|
||||
public final static long BUILD = 1;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
@ -13,12 +13,14 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.crypto.KeyStoreUtil;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PSSLSocketFactory;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
|
||||
@ -174,6 +176,7 @@ class SSLClientListenerRunner extends ClientListenerRunner {
|
||||
_log.info("Listening on port " + _port + " of the specific interface: " + listenInterface);
|
||||
rv = _factory.createServerSocket(_port, 0, InetAddress.getByName(listenInterface));
|
||||
}
|
||||
I2PSSLSocketFactory.setProtocolsAndCiphers((SSLServerSocket) rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -110,10 +110,10 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
||||
private static final long SESSION_TAG_EXPIRATION_WINDOW = 90 * 1000;
|
||||
|
||||
/**
|
||||
* a few MB? how about 16MB!
|
||||
* a few MB? how about 24 MB!
|
||||
* This is the max size of _inboundTagSets.
|
||||
*/
|
||||
public final static int MAX_INBOUND_SESSION_TAGS = 500 * 1000; // this will consume at most a few MB
|
||||
public final static int MAX_INBOUND_SESSION_TAGS = 750 * 1000;
|
||||
|
||||
/**
|
||||
* This was 100 since 0.6.1.10 (50 before that). It's important because:
|
||||
@ -584,7 +584,7 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
||||
int recent = 0;
|
||||
int tags = 0;
|
||||
int toRemove = overage * 2;
|
||||
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
|
||||
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
|
||||
List<TagSet> removed = new ArrayList<TagSet>(toRemove);
|
||||
synchronized (_inboundTagSets) {
|
||||
for (TagSet set : _inboundTagSets.values()) {
|
||||
@ -593,12 +593,18 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
||||
absurd++;
|
||||
if (size > 100)
|
||||
large++;
|
||||
if (now >= set.getDate())
|
||||
if (set.getDate() - now < 3*60*1000) {
|
||||
// expiration is 12 minutes, so these are older than 9 minutes
|
||||
old++;
|
||||
else if (set.getDate() - now > 10*60*1000)
|
||||
removed.add(set);
|
||||
continue;
|
||||
} else if (set.getDate() - now > 8*60*1000) {
|
||||
// expiration is 12 minutes, so these were created in last 4 minutes
|
||||
recent++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((removed.size() < (toRemove)) || (now >= set.getDate()))
|
||||
if (removed.size() < toRemove)
|
||||
removed.add(set);
|
||||
}
|
||||
for (int i = 0; i < removed.size(); i++) {
|
||||
@ -609,11 +615,10 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.CRIT))
|
||||
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! removing " + removed
|
||||
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! removed " + removed.size()
|
||||
+ " tag sets arbitrarily, with " + tags + " tags,"
|
||||
+ "where there are " + old + " long lasting sessions, "
|
||||
+ recent + " ones created in the last minute, and "
|
||||
+ recent + " ones created in the last few minutes, and "
|
||||
+ large + " sessions with more than 100 tags (and "
|
||||
+ absurd + " with more than 1000!), leaving a total of "
|
||||
+ _inboundTagSets.size() + " tags behind");
|
||||
|
@ -220,6 +220,11 @@ class OutboundClientMessageJobHelper {
|
||||
ackClove.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE));
|
||||
DeliveryStatusMessage dsm = buildDSM(ctx, replyToken);
|
||||
GarlicMessage msg = wrapDSM(ctx, skm, dsm);
|
||||
if (msg == null) {
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn("Failed to wrap ack clove");
|
||||
return null;
|
||||
}
|
||||
ackClove.setPayload(msg);
|
||||
// this does nothing, the clove is not separately encrypted
|
||||
//ackClove.setRecipient(ctx.router().getRouterInfo());
|
||||
|
@ -72,9 +72,9 @@ public class CreateRouterInfoJob extends JobImpl {
|
||||
|
||||
/**
|
||||
* Writes 6 files: router.info (standard RI format),
|
||||
* router.keys2, and 4 individual key files under keyBackup/
|
||||
* router.keys.dat, and 4 individual key files under keyBackup/
|
||||
*
|
||||
* router.keys2 file format: This is the
|
||||
* router.keys.dat file format: This is the
|
||||
* same "eepPriv.dat" format used by the client code,
|
||||
* as documented in PrivateKeyFile.
|
||||
*
|
||||
|
@ -66,7 +66,7 @@ class LoadRouterInfoJob extends JobImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads router.info and router.keys2 or router.keys.
|
||||
* Loads router.info and either router.keys.dat or router.keys.
|
||||
*
|
||||
* See CreateRouterInfoJob for file formats
|
||||
*/
|
||||
|
@ -121,6 +121,7 @@ class EstablishState {
|
||||
private static final int HXY_SIZE = 32; //Hash.HASH_LENGTH;
|
||||
private static final int HXY_TSB_PAD_SIZE = HXY_SIZE + 4 + 12; // 48
|
||||
|
||||
private static final Object _stateLock = new Object();
|
||||
protected State _state;
|
||||
|
||||
private enum State {
|
||||
@ -193,6 +194,13 @@ class EstablishState {
|
||||
_curDecrypted = SimpleByteCache.acquire(AES_SIZE);
|
||||
}
|
||||
|
||||
/** @since 0.9.16 */
|
||||
private void changeState(State state) {
|
||||
synchronized (_stateLock) {
|
||||
_state = state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the contents of the buffer as part of the handshake. if the
|
||||
* handshake is completed and there is more data remaining, the data are
|
||||
@ -203,8 +211,10 @@ class EstablishState {
|
||||
* will return it to the pool.
|
||||
*/
|
||||
public synchronized void receive(ByteBuffer src) {
|
||||
if (_state == State.VERIFIED || _state == State.CORRUPT)
|
||||
throw new IllegalStateException(prefix() + "received unexpected data on " + _con);
|
||||
synchronized(_stateLock) {
|
||||
if (_state == State.VERIFIED || _state == State.CORRUPT)
|
||||
throw new IllegalStateException(prefix() + "received unexpected data on " + _con);
|
||||
}
|
||||
if (!src.hasRemaining())
|
||||
return; // nothing to receive
|
||||
|
||||
@ -229,6 +239,9 @@ class EstablishState {
|
||||
* will return it to the pool.
|
||||
*
|
||||
* Caller must synch.
|
||||
*
|
||||
* FIXME none of the _state comparisons use _stateLock, but whole thing
|
||||
* is synchronized, should be OK. See isComplete()
|
||||
*/
|
||||
private void receiveInbound(ByteBuffer src) {
|
||||
while (_state == State.IB_INIT && src.hasRemaining()) {
|
||||
@ -243,7 +256,7 @@ class EstablishState {
|
||||
// }
|
||||
//}
|
||||
if (_received >= XY_SIZE)
|
||||
_state = State.IB_GOT_X;
|
||||
changeState(State.IB_GOT_X);
|
||||
}
|
||||
while (_state == State.IB_GOT_X && src.hasRemaining()) {
|
||||
int i = _received - XY_SIZE;
|
||||
@ -252,7 +265,7 @@ class EstablishState {
|
||||
_hX_xor_bobIdentHash[i] = c;
|
||||
//if (_log.shouldLog(Log.DEBUG)) _log.debug("recv bih" + (int)c + " received=" + _received);
|
||||
if (i >= HXY_SIZE - 1)
|
||||
_state = State.IB_GOT_HX;
|
||||
changeState(State.IB_GOT_HX);
|
||||
}
|
||||
|
||||
if (_state == State.IB_GOT_HX) {
|
||||
@ -325,7 +338,7 @@ class EstablishState {
|
||||
System.arraycopy(_e_hXY_tsB, 0, write, XY_SIZE, HXY_TSB_PAD_SIZE);
|
||||
|
||||
// ok, now that is prepared, we want to actually send it, so make sure we are up for writing
|
||||
_state = State.IB_SENT_Y;
|
||||
changeState(State.IB_SENT_Y);
|
||||
_transport.getPumper().wantsWrite(_con, write);
|
||||
if (!src.hasRemaining()) return;
|
||||
} catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
|
||||
@ -370,7 +383,7 @@ class EstablishState {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(prefix() + "got the RI size: " + sz);
|
||||
_aliceIdentSize = sz;
|
||||
_state = State.IB_GOT_RI_SIZE;
|
||||
changeState(State.IB_GOT_RI_SIZE);
|
||||
|
||||
// We must defer the calculations for total size of the message until
|
||||
// we get the full alice ident so
|
||||
@ -401,7 +414,7 @@ class EstablishState {
|
||||
fail("Unsupported sig type");
|
||||
return;
|
||||
}
|
||||
_state = State.IB_GOT_RI;
|
||||
changeState(State.IB_GOT_RI);
|
||||
// handle variable signature size
|
||||
_sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + type.getSigLen();
|
||||
int rem = (_sz_aliceIdent_tsA_padding_aliceSigSize % AES_SIZE);
|
||||
@ -453,6 +466,9 @@ class EstablishState {
|
||||
* will return it to the pool.
|
||||
*
|
||||
* Caller must synch.
|
||||
*
|
||||
* FIXME none of the _state comparisons use _stateLock, but whole thing
|
||||
* is synchronized, should be OK. See isComplete()
|
||||
*/
|
||||
private void receiveOutbound(ByteBuffer src) {
|
||||
// recv Y+E(H(X+Y)+tsB, sk, Y[239:255])
|
||||
@ -466,7 +482,7 @@ class EstablishState {
|
||||
_dh.getSessionKey(); // force the calc
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(prefix()+"DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
|
||||
_state = State.OB_GOT_Y;
|
||||
changeState(State.OB_GOT_Y);
|
||||
} catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
|
||||
_context.statManager().addRateData("ntcp.invalidDH", 1);
|
||||
fail("Invalid X", e);
|
||||
@ -500,7 +516,7 @@ class EstablishState {
|
||||
return;
|
||||
}
|
||||
SimpleByteCache.release(h);
|
||||
_state = State.OB_GOT_HXY;
|
||||
changeState(State.OB_GOT_HXY);
|
||||
_tsB = DataHelper.fromLong(hXY_tsB, HXY_SIZE, 4); // their (Bob's) timestamp in seconds
|
||||
_tsA = (_context.clock().now() + 500) / 1000; // our (Alice's) timestamp in seconds
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -573,7 +589,7 @@ class EstablishState {
|
||||
//_log.debug(prefix() + "encrypted response to Bob: " + Base64.encode(_prevEncrypted));
|
||||
//}
|
||||
// send 'er off (when the bw limiter says, etc)
|
||||
_state = State.OB_SENT_RI;
|
||||
changeState(State.OB_SENT_RI);
|
||||
_transport.getPumper().wantsWrite(_con, _prevEncrypted);
|
||||
}
|
||||
}
|
||||
@ -607,7 +623,7 @@ class EstablishState {
|
||||
_received++;
|
||||
|
||||
if (off >= _e_bobSig.length) {
|
||||
_state = State.OB_GOT_SIG;
|
||||
changeState(State.OB_GOT_SIG);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug(prefix() + "received E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev): " + Base64.encode(_e_bobSig));
|
||||
byte bobSig[] = new byte[_e_bobSig.length];
|
||||
@ -634,7 +650,6 @@ class EstablishState {
|
||||
_context.statManager().addRateData("ntcp.invalidSignature", 1);
|
||||
fail("Signature was invalid - attempt to spoof " + _con.getRemotePeer().calculateHash().toBase64() + "?");
|
||||
} else {
|
||||
_state = State.VERIFIED;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(prefix() + "signature verified from Bob. done!");
|
||||
prepareExtra(src);
|
||||
@ -642,11 +657,12 @@ class EstablishState {
|
||||
System.arraycopy(_prevEncrypted, _prevEncrypted.length-AES_SIZE, nextWriteIV, 0, AES_SIZE);
|
||||
// this does not copy the nextWriteIV, do not release to cache
|
||||
_con.finishOutboundEstablishment(_dh.getSessionKey(), (_tsA-_tsB), nextWriteIV, _e_bobSig); // skew in seconds
|
||||
releaseBufs();
|
||||
releaseBufs(true);
|
||||
// if socket gets closed this will be null - prevent NPE
|
||||
InetAddress ia = _con.getChannel().socket().getInetAddress();
|
||||
if (ia != null)
|
||||
_transport.setIP(_con.getRemotePeer().calculateHash(), ia.getAddress());
|
||||
changeState(State.VERIFIED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -655,10 +671,24 @@ class EstablishState {
|
||||
}
|
||||
|
||||
/** did the handshake fail for some reason? */
|
||||
public synchronized boolean isCorrupt() { return _state == State.CORRUPT; }
|
||||
public boolean isCorrupt() {
|
||||
synchronized(_stateLock) {
|
||||
return _state == State.CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return is the handshake complete and valid? */
|
||||
public synchronized boolean isComplete() { return _state == State.VERIFIED; }
|
||||
/**
|
||||
* If synchronized on this, fails with
|
||||
* deadlocks from all over via CSFI.isEstablished().
|
||||
* Also CSFI.getFramedAveragePeerClockSkew().
|
||||
*
|
||||
* @return is the handshake complete and valid?
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
synchronized(_stateLock) {
|
||||
return _state == State.VERIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We are Alice.
|
||||
@ -667,13 +697,17 @@ class EstablishState {
|
||||
* This method sends message #1 to Bob.
|
||||
*/
|
||||
public synchronized void prepareOutbound() {
|
||||
if (_state == State.OB_INIT) {
|
||||
boolean shouldSend;
|
||||
synchronized(_stateLock) {
|
||||
shouldSend = _state == State.OB_INIT;
|
||||
}
|
||||
if (shouldSend) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(prefix() + "send X");
|
||||
byte toWrite[] = new byte[XY_SIZE + _hX_xor_bobIdentHash.length];
|
||||
System.arraycopy(_X, 0, toWrite, 0, XY_SIZE);
|
||||
System.arraycopy(_hX_xor_bobIdentHash, 0, toWrite, XY_SIZE, _hX_xor_bobIdentHash.length);
|
||||
_state = State.OB_SENT_X;
|
||||
changeState(State.OB_SENT_X);
|
||||
_transport.getPumper().wantsWrite(_con, toWrite);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@ -815,7 +849,6 @@ class EstablishState {
|
||||
_log.debug(prefix()+"Clock skew: " + diff + " ms");
|
||||
}
|
||||
|
||||
_state = State.VERIFIED;
|
||||
sendInboundConfirm(_aliceIdent, tsA);
|
||||
_con.setRemotePeer(_aliceIdent);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -824,9 +857,10 @@ class EstablishState {
|
||||
System.arraycopy(_e_bobSig, _e_bobSig.length-AES_SIZE, iv, 0, AES_SIZE);
|
||||
// this does not copy the IV, do not release to cache
|
||||
_con.finishInboundEstablishment(_dh.getSessionKey(), (tsA-_tsB), iv, _prevEncrypted); // skew in seconds
|
||||
releaseBufs();
|
||||
releaseBufs(true);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(prefix()+"Verified remote peer as " + _aliceIdent.calculateHash());
|
||||
changeState(State.VERIFIED);
|
||||
} else {
|
||||
_context.statManager().addRateData("ntcp.invalidInboundSignature", 1);
|
||||
fail("Peer verification failed - spoof of " + _aliceIdent.calculateHash() + "?");
|
||||
@ -917,28 +951,30 @@ class EstablishState {
|
||||
|
||||
/** Caller must synch. */
|
||||
private void fail(String reason, Exception e, boolean bySkew) {
|
||||
if (_state == State.CORRUPT || _state == State.VERIFIED)
|
||||
return;
|
||||
_state = State.CORRUPT;
|
||||
synchronized(_stateLock) {
|
||||
if (_state == State.CORRUPT || _state == State.VERIFIED)
|
||||
return;
|
||||
changeState(State.CORRUPT);
|
||||
}
|
||||
_failedBySkew = bySkew;
|
||||
_err = reason;
|
||||
_e = e;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(prefix()+"Failed to establish: " + _err, e);
|
||||
releaseBufs();
|
||||
releaseBufs(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call once. Caller must synch.
|
||||
* @since 0.9.16
|
||||
*/
|
||||
private void releaseBufs() {
|
||||
private void releaseBufs(boolean isVerified) {
|
||||
// null or longer for OB
|
||||
if (_prevEncrypted != null && _prevEncrypted.length == AES_SIZE)
|
||||
SimpleByteCache.release(_prevEncrypted);
|
||||
// Do not release _curEncrypted if verified, it is passed to
|
||||
// NTCPConnection to use as the IV
|
||||
if (_state != State.VERIFIED)
|
||||
if (!isVerified)
|
||||
SimpleByteCache.release(_curEncrypted);
|
||||
SimpleByteCache.release(_curDecrypted);
|
||||
SimpleByteCache.release(_hX_xor_bobIdentHash);
|
||||
|
@ -958,8 +958,8 @@ class EstablishmentManager {
|
||||
if (!oldId.equals(newId)) {
|
||||
_outboundStates.remove(oldId);
|
||||
_outboundStates.put(newId, state);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("RR replaced " + oldId + " with " + newId + ", claimed address was " + claimed);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("RR replaced " + oldId + " with " + newId + ", claimed address was " + claimed);
|
||||
}
|
||||
//
|
||||
if (claimed != null)
|
||||
@ -980,17 +980,17 @@ class EstablishmentManager {
|
||||
if (state != null) {
|
||||
boolean sendNow = state.receiveHolePunch();
|
||||
if (sendNow) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Hole punch from " + state + ", sending SessionRequest now");
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Hole punch from " + state + ", sending SessionRequest now");
|
||||
notifyActivity();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Hole punch from " + state + ", already sent SessionRequest");
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Hole punch from " + state + ", already sent SessionRequest");
|
||||
}
|
||||
} else {
|
||||
// HolePunch received before RelayResponse, and we didn't know the IP/port, or it changed
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("No state found for hole punch from " + from + " port " + fromPort);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("No state found for hole punch from " + from + " port " + fromPort);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,10 +72,14 @@ class InboundMessageState implements CDQEntry {
|
||||
_log = ctx.logManager().getLog(InboundMessageState.class);
|
||||
_messageId = messageId;
|
||||
_from = from;
|
||||
if (data.readMessageIsLast(dataFragment))
|
||||
_fragments = new ByteArray[1 + data.readMessageFragmentNum(dataFragment)];
|
||||
else
|
||||
if (data.readMessageIsLast(dataFragment)) {
|
||||
int num = 1 + data.readMessageFragmentNum(dataFragment);
|
||||
if (num > MAX_FRAGMENTS)
|
||||
throw new DataFormatException("corrupt - too many fragments: " + num);
|
||||
_fragments = new ByteArray[num];
|
||||
} else {
|
||||
_fragments = new ByteArray[MAX_FRAGMENTS];
|
||||
}
|
||||
_lastFragment = -1;
|
||||
_completeSize = -1;
|
||||
_receiveBegin = ctx.clock().now();
|
||||
@ -222,8 +226,10 @@ class InboundMessageState implements CDQEntry {
|
||||
return _completeSize;
|
||||
}
|
||||
|
||||
/** FIXME synch here or PeerState.fetchPartialACKs() */
|
||||
public ACKBitfield createACKBitfield() {
|
||||
int sz = (_lastFragment >= 0) ? _lastFragment + 1 : _fragments.length;
|
||||
int last = _lastFragment;
|
||||
int sz = (last >= 0) ? last + 1 : _fragments.length;
|
||||
return new PartialBitfield(_messageId, _fragments, sz);
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ class OutboundEstablishState {
|
||||
return _sentX;
|
||||
}
|
||||
|
||||
/**x
|
||||
/**
|
||||
* The remote side (Bob) - note that in some places he's called Charlie.
|
||||
* Warning - may change after introduction. May be null before introduction.
|
||||
*/
|
||||
@ -618,8 +618,8 @@ class OutboundEstablishState {
|
||||
if (_requestSentCount > 0)
|
||||
return false;
|
||||
long now = _context.clock().now();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(toString() + " accelerating SessionRequest by " + (_nextSend - now) + " ms");
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(toString() + " accelerating SessionRequest by " + (_nextSend - now) + " ms");
|
||||
_nextSend = now;
|
||||
return true;
|
||||
}
|
||||
|
@ -434,7 +434,9 @@ class PacketBuilder {
|
||||
off += 4;
|
||||
for (int curByte = 0; curByte < size; curByte++) {
|
||||
if (curByte + 1 < size)
|
||||
data[off] |= (byte)(1 << 7);
|
||||
data[off] = (byte)(1 << 7);
|
||||
else
|
||||
data[off] = 0;
|
||||
|
||||
for (int curBit = 0; curBit < 7; curBit++) {
|
||||
if (bitfield.received(curBit + 7*curByte))
|
||||
@ -467,7 +469,7 @@ class PacketBuilder {
|
||||
DataHelper.toLong(data, off, 4, state.getMessageId());
|
||||
off += 4;
|
||||
|
||||
data[off] |= fragment << 1;
|
||||
data[off] = (byte) (fragment << 1);
|
||||
if (fragment == state.getFragmentCount() - 1)
|
||||
data[off] |= 1; // isLast
|
||||
off++;
|
||||
@ -621,8 +623,7 @@ class PacketBuilder {
|
||||
off++;
|
||||
for (int i = 0; i < ackBitfields.size(); i++) {
|
||||
ACKBitfield bitfield = ackBitfields.get(i);
|
||||
// no, this will corrupt the packet
|
||||
//if (bitfield.receivedComplete()) continue;
|
||||
if (bitfield.receivedComplete()) continue;
|
||||
DataHelper.toLong(data, off, 4, bitfield.getMessageId());
|
||||
off += 4;
|
||||
// only send what we have to
|
||||
@ -633,7 +634,9 @@ class PacketBuilder {
|
||||
size++;
|
||||
for (int curByte = 0; curByte < size; curByte++) {
|
||||
if (curByte + 1 < size)
|
||||
data[off] |= (byte)(1 << 7);
|
||||
data[off] = (byte)(1 << 7);
|
||||
else
|
||||
data[off] = 0;
|
||||
|
||||
for (int curBit = 0; curBit < 7; curBit++) {
|
||||
if (bitfield.received(curBit + 7*curByte))
|
||||
@ -878,7 +881,7 @@ class PacketBuilder {
|
||||
}
|
||||
|
||||
// now for the body
|
||||
data[off] |= fragmentNum << 4;
|
||||
data[off] = (byte) (fragmentNum << 4);
|
||||
data[off] |= (numFragments & 0xF);
|
||||
off++;
|
||||
|
||||
|
Reference in New Issue
Block a user