if I'm making this backwards incompatible, I might as well clean up the rest, 'eh?

* removed SourceRouteBlock & SourceRouteReplyMessage, as they're a redundant concept
that 1) takes up bandwidth 2) takes up CPU 3) smell funny.
now the TunnelCreateMessage includes a replyTag, replyKey, replyTunnel, and
replyGateway that they garlic encrypt their ACK/NACK through and with.

* tunnelCreateMessage doesn't need a seperate ACK - either we get a
TunnelCreateStatusMessage back or we don't.

* message structure mods for unique tunnel ID per hop (though currently all hops have
the same tunnel ID)
This commit is contained in:
jrandom
2004-07-27 22:04:02 +00:00
committed by zzz
parent 0ed95bbdf1
commit 60c7db0733
27 changed files with 274 additions and 1152 deletions

View File

@@ -144,7 +144,8 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
byte compressed[] = new byte[compressedSize];
int read = DataHelper.read(in, compressed);
if (read != compressedSize)
throw new I2NPMessageException("Invalid compressed data size");
throw new I2NPMessageException("Invalid compressed data size (expected "
+ compressedSize + " read " + read + ")");
ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed));
_info.readBytes(bais);
} else {

View File

@@ -34,25 +34,8 @@ public class GarlicClove extends DataStructureImpl {
private long _cloveId;
private Date _expiration;
private Certificate _certificate;
private int _replyAction;
private SourceRouteBlock _sourceRouteBlock;
private I2NPMessageHandler _handler;
/** No action requested with the source route block */
public final static int ACTION_NONE = 0;
/**
* A DeliveryStatusMessage is requested with the source route block using
* the cloveId as the id received
*
*/
public final static int ACTION_STATUS = 1;
/**
* No DeliveryStatusMessage is requested, but the source route block is
* included for message specific replies
*
*/
public final static int ACTION_MESSAGE_SPECIFIC = 2;
public GarlicClove(RouterContext context) {
_context = context;
_log = context.logManager().getLog(GarlicClove.class);
@@ -62,8 +45,6 @@ public class GarlicClove extends DataStructureImpl {
setCloveId(-1);
setExpiration(null);
setCertificate(null);
setSourceRouteBlockAction(ACTION_NONE);
setSourceRouteBlock(null);
}
public DeliveryInstructions getInstructions() { return _instructions; }
@@ -76,10 +57,6 @@ public class GarlicClove extends DataStructureImpl {
public void setExpiration(Date exp) { _expiration = exp; }
public Certificate getCertificate() { return _certificate; }
public void setCertificate(Certificate cert) { _certificate = cert; }
public int getSourceRouteBlockAction() { return _replyAction; }
public void setSourceRouteBlockAction(int action) { _replyAction = action; }
public SourceRouteBlock getSourceRouteBlock() { return _sourceRouteBlock; }
public void setSourceRouteBlock(SourceRouteBlock block) { _sourceRouteBlock = block; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_instructions = new DeliveryInstructions();
@@ -99,12 +76,6 @@ public class GarlicClove extends DataStructureImpl {
_certificate.readBytes(in);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Read cert: " + _certificate);
int replyStyle = (int)DataHelper.readLong(in, 1);
setSourceRouteBlockAction(replyStyle);
if (replyStyle != ACTION_NONE) {
_sourceRouteBlock = new SourceRouteBlock();
_sourceRouteBlock.readBytes(in);
}
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
@@ -119,28 +90,23 @@ public class GarlicClove extends DataStructureImpl {
error.append("Expiration is null ");
if (_certificate == null)
error.append("Certificate is null ");
if (_replyAction < 0)
error.append("Reply action is < 0 [").append(_replyAction).append("] ");;
if (error.length() > 0)
throw new DataFormatException(error.toString());
if ( (_replyAction != 0) && (_sourceRouteBlock == null) )
throw new DataFormatException("Source route block must be specified for non-null action");
_instructions.writeBytes(out);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Wrote instructions: " + _instructions);
_msg.writeBytes(out);
DataHelper.writeLong(out, 4, _cloveId);
DataHelper.writeDate(out, _expiration);
if (_log.shouldLog(Log.DEBUG))
_log.debug("CloveID written: " + _cloveId + " expiration written: "
+ _expiration);
_certificate.writeBytes(out);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Written cert: " + _certificate);
DataHelper.writeLong(out, 1, _replyAction);
if ( (_replyAction != 0) && (_sourceRouteBlock != null) )
_sourceRouteBlock.writeBytes(out);
if (error.length() > 0)
throw new DataFormatException(error.toString());
_instructions.writeBytes(out);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Wrote instructions: " + _instructions);
_msg.writeBytes(out);
DataHelper.writeLong(out, 4, _cloveId);
DataHelper.writeDate(out, _expiration);
if (_log.shouldLog(Log.DEBUG))
_log.debug("CloveID written: " + _cloveId + " expiration written: "
+ _expiration);
_certificate.writeBytes(out);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Written cert: " + _certificate);
}
public boolean equals(Object obj) {
@@ -148,22 +114,18 @@ public class GarlicClove extends DataStructureImpl {
return false;
GarlicClove clove = (GarlicClove)obj;
return DataHelper.eq(getCertificate(), clove.getCertificate()) &&
DataHelper.eq(getCloveId(), clove.getCloveId()) &&
DataHelper.eq(getData(), clove.getData()) &&
DataHelper.eq(getExpiration(), clove.getExpiration()) &&
DataHelper.eq(getInstructions(), clove.getInstructions()) &&
DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) &&
(getSourceRouteBlockAction() == clove.getSourceRouteBlockAction());
DataHelper.eq(getCloveId(), clove.getCloveId()) &&
DataHelper.eq(getData(), clove.getData()) &&
DataHelper.eq(getExpiration(), clove.getExpiration()) &&
DataHelper.eq(getInstructions(), clove.getInstructions());
}
public int hashCode() {
return DataHelper.hashCode(getCertificate()) +
(int)getCloveId() +
DataHelper.hashCode(getData()) +
DataHelper.hashCode(getExpiration()) +
DataHelper.hashCode(getInstructions()) +
DataHelper.hashCode(getSourceRouteBlock()) +
getSourceRouteBlockAction();
(int)getCloveId() +
DataHelper.hashCode(getData()) +
DataHelper.hashCode(getExpiration()) +
DataHelper.hashCode(getInstructions());
}
public String toString() {
@@ -173,8 +135,6 @@ public class GarlicClove extends DataStructureImpl {
buf.append("\n\tCertificate: ").append(getCertificate());
buf.append("\n\tClove ID: ").append(getCloveId());
buf.append("\n\tExpiration: ").append(getExpiration());
buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction());
buf.append("\n\tSource route block: ").append(getSourceRouteBlock());
buf.append("\n\tData: ").append(getData());
buf.append("]");
return buf.toString();

View File

@@ -73,8 +73,6 @@ public class I2NPMessageHandler {
return new TunnelMessage(_context);
case DataMessage.MESSAGE_TYPE:
return new DataMessage(_context);
case SourceRouteReplyMessage.MESSAGE_TYPE:
return new SourceRouteReplyMessage(_context);
case TunnelCreateMessage.MESSAGE_TYPE:
return new TunnelCreateMessage(_context);
case TunnelCreateStatusMessage.MESSAGE_TYPE:

View File

@@ -1,228 +0,0 @@
package net.i2p.data.i2np;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import net.i2p.I2PAppContext;
import net.i2p.data.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.util.Log;
/**
* Defines a single hop of a source routed message, as usable for building a
* SourceRouteReplyMessage
*
* @author jrandom
*/
public class SourceRouteBlock extends DataStructureImpl {
private final static Log _log = new Log(SourceRouteBlock.class);
private Hash _router;
private byte[] _data;
private SessionKey _key;
private byte[] _tag;
private DeliveryInstructions _decryptedInstructions;
private long _decryptedMessageId;
private Certificate _decryptedCertificate;
private long _decryptedExpiration;
public SourceRouteBlock() {
setRouter(null);
setData(null);
setKey(null);
setTag((byte[])null);
_decryptedInstructions = null;
_decryptedMessageId = -1;
_decryptedCertificate = null;
_decryptedExpiration = -1;
}
/**
* Get the router through which replies using this source route block must
* be sent (as the getData() is encrypted for their eyes only)
*
*/
public Hash getRouter() { return _router; }
public void setRouter(Hash router) { _router= router; }
/**
* Get the encrypted header. After decryption (via ElGamal+AES as defined
* in the data structures spec), this array contains:
* DeliveryInstructions
* 4 byte Integer for a message ID
* Certificate
* Date of expiration for replies
*
*/
public byte[] getData() { return _data; }
private void setData(byte data[]) { _data = data; }
/**
* Retrieve the session key which may be used in conjunction with the tag
* to encrypt a garlic message and send it as a reply to this message.
* The encryption would follow scenario 2 of the ElGamal+AES encryption method
* defined in the data structures spec.
*
*/
public SessionKey getKey() { return _key; }
public void setKey(SessionKey key) { _key = key; }
/**
* Get the tag made available for use in conjunction with the getKey() to
* ElGamal+AES encrypt a garlic message without knowing the public key to
* which the message is destined
*
*/
public byte[] getTag() { return _tag; }
public void setTag(SessionTag tag) { setTag(tag.getData()); }
public void setTag(byte tag[]) {
if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) )
throw new IllegalArgumentException("Tag must be either null or 32 bytes");
_tag = tag;
}
/**
* After decryptData, this contains the delivery instructions for this block
*/
public DeliveryInstructions getDecryptedInstructions() { return _decryptedInstructions; }
/**
* After decryptData, this contains the message ID to be used with this block
*/
public long getDecryptedMessageId() { return _decryptedMessageId; }
/**
* After decryptData, this contains the Certificate 'paying' for the forwarding according to
* this block
*/
public Certificate getDecryptedCertificate() { return _decryptedCertificate; }
/**
* After decryptData, this contains the date after which this block should not be forwarded
*/
public long getDecryptedExpiration() { return _decryptedExpiration; }
/**
* Set the raw data with the formatted and encrypted options specified
*
* @param instructions Where a message bearing this block should be sent
* @param messageId ID of the message for this block (not repeatable)
* @param expiration date after which this block expires
* @param replyThrough Encryption key of the router to whom this block is specified (not
* the router specified in the delivery instructions!)
*
* @throws DataFormatException if the data is invalid or could not be encrypted
*/
public void setData(I2PAppContext ctx, DeliveryInstructions instructions,
long messageId, Certificate cert, long expiration,
PublicKey replyThrough) throws DataFormatException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
_decryptedInstructions = instructions;
_decryptedMessageId = messageId;
_decryptedCertificate = cert;
_decryptedExpiration = expiration;
instructions.writeBytes(baos);
DataHelper.writeLong(baos, 4, messageId);
cert.writeBytes(baos);
DataHelper.writeDate(baos, new Date(expiration));
int paddedSize = 256;
SessionKey sessKey = null;
SessionTag tag = null;
if (instructions.getDelayRequested()) {
// always use a new key if we're delaying, since the reply block may not be used within the
// window of a session
sessKey = ctx.keyGenerator().generateSessionKey();
tag = null;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Delay requested - creating a new session key");
} else {
sessKey = ctx.sessionKeyManager().getCurrentKey(replyThrough);
if (sessKey == null) {
sessKey = ctx.keyGenerator().generateSessionKey();
tag = null;
if (_log.shouldLog(Log.DEBUG))
_log.debug("No delay requested, but no session key is known");
} else {
tag = ctx.sessionKeyManager().consumeNextAvailableTag(replyThrough, sessKey);
}
}
byte encData[] = ctx.elGamalAESEngine().encrypt(baos.toByteArray(), replyThrough,
sessKey, null, tag, paddedSize);
setData(encData);
} catch (IOException ioe) {
throw new DataFormatException("Error writing out the source route block data", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error writing out the source route block data", dfe);
}
}
public void readBytes(InputStream in) throws DataFormatException, IOException {
_router = new Hash();
_router.readBytes(in);
int size = (int)DataHelper.readLong(in, 2);
_data = new byte[size];
int read = read(in, _data);
if (read != _data.length)
throw new DataFormatException("Incorrect # of bytes read for source route block: " + read);
_key = new SessionKey();
_key.readBytes(in);
_tag = new byte[32];
read = read(in, _tag);
if (read != _tag.length)
throw new DataFormatException("Incorrect # of bytes read for session tag: " + read);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if ( (_router == null) || (_data == null) || (_key == null) || (_tag == null) || (_tag.length != 32) )
throw new DataFormatException("Insufficient data to write");
_router.writeBytes(out);
DataHelper.writeLong(out, 2, _data.length);
out.write(_data);
_key.writeBytes(out);
out.write(_tag);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof SourceRouteBlock))
return false;
SourceRouteBlock block = (SourceRouteBlock)obj;
return DataHelper.eq(getRouter(), block.getRouter()) &&
DataHelper.eq(getData(), block.getData()) &&
DataHelper.eq(getKey(), block.getKey()) &&
DataHelper.eq(getTag(), block.getTag());
}
public int hashCode() {
return DataHelper.hashCode(getRouter()) +
DataHelper.hashCode(getData()) +
DataHelper.hashCode(getKey()) +
DataHelper.hashCode(getTag());
}
public String toString() {
StringBuffer buf = new StringBuffer(128);
buf.append("[SourceRouteBlock: ");
buf.append("\n\tRouter: ").append(getRouter());
buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length));
buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0)));
buf.append("\n\tKey: ").append(getKey());
buf.append("]");
return buf.toString();
}
}

View File

@@ -1,164 +0,0 @@
package net.i2p.data.i2np;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import net.i2p.I2PAppContext;
import net.i2p.data.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.PrivateKey;
import net.i2p.util.Log;
/**
* Defines a message directed by a source route block to deliver a message to an
* unknown location.
*
* @author jrandom
*/
public class SourceRouteReplyMessage extends I2NPMessageImpl {
private final static Log _log = new Log(SourceRouteReplyMessage.class);
public final static int MESSAGE_TYPE = 13;
private byte _encryptedHeader[];
private I2NPMessage _message;
private DeliveryInstructions _decryptedInstructions;
private long _decryptedMessageId;
private Certificate _decryptedCertificate;
private long _decryptedExpiration;
private I2NPMessageHandler _handler;
public SourceRouteReplyMessage(I2PAppContext context) {
super(context);
_handler = new I2NPMessageHandler(context);
_encryptedHeader = null;
_message = null;
_decryptedInstructions = null;
_decryptedMessageId = -1;
_decryptedCertificate = null;
_decryptedExpiration = -1;
}
/**
* Retrieve the message being sent as a reply
*/
public I2NPMessage getMessage() { return _message; }
public void setMessage(I2NPMessage message) { _message = message; }
public void setEncryptedHeader(byte header[]) { _encryptedHeader = header; }
/**
* After decryptHeader, this contains the delivery instructions for this block
*/
public DeliveryInstructions getDecryptedInstructions() { return _decryptedInstructions; }
/**
* After decryptHeader, this contains the message ID to be used with this block
*/
public long getDecryptedMessageId() { return _decryptedMessageId; }
/**
* After decryptHeader, this contains the Certificate 'paying' for the forwarding according to
* this block
*/
public Certificate getDecryptedCertificate() { return _decryptedCertificate; }
/**
* After decryptHeader, this contains the date after which this block should not be forwarded
*/
public long getDecryptedExpiration() { return _decryptedExpiration; }
/**
* Decrypt the header and store it in the various getDecryptedXYZ() properties
*
* @throws DataFormatException if the decryption fails or if the data is somehow malformed
*/
public void decryptHeader(PrivateKey key) throws DataFormatException {
if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) )
throw new DataFormatException("No header to decrypt");
byte decr[] = _context.elGamalAESEngine().decrypt(_encryptedHeader, key);
if (decr == null)
throw new DataFormatException("Decrypted data is null");
try {
ByteArrayInputStream bais = new ByteArrayInputStream(decr);
_decryptedInstructions = new DeliveryInstructions();
_decryptedInstructions.readBytes(bais);
_decryptedMessageId = DataHelper.readLong(bais, 4);
_decryptedCertificate = new Certificate();
_decryptedCertificate.readBytes(bais);
_decryptedExpiration = DataHelper.readDate(bais).getTime();
} catch (IOException ioe) {
throw new DataFormatException("Error reading the source route reply header", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error reading the source route reply header", dfe);
}
}
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE)
throw new I2NPMessageException("Message type is incorrect for this message");
try {
int headerSize = (int)DataHelper.readLong(in, 2);
_encryptedHeader = new byte[headerSize];
int read = read(in, _encryptedHeader);
if (read != headerSize)
throw new DataFormatException("Not enough bytes to read the header (read = " + read
+ ", required = " + headerSize + ")");
_message = _handler.readMessage(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_encryptedHeader == null) || (_message == null) )
throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
try {
DataHelper.writeLong(os, 2, _encryptedHeader.length);
os.write(_encryptedHeader);
_message.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(_encryptedHeader) +
DataHelper.hashCode(_message);
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof SourceRouteReplyMessage) ) {
SourceRouteReplyMessage msg = (SourceRouteReplyMessage)object;
return DataHelper.eq(_message,msg._message) &&
DataHelper.eq(_encryptedHeader,msg._encryptedHeader);
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[SourceRouteReplyMessage: ");
buf.append("\n\tHeader: ").append(DataHelper.toString(_encryptedHeader, 64));
buf.append("\n\tMessage: ").append(_message);
buf.append("]");
return buf.toString();
}
}

View File

@@ -18,6 +18,8 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.util.Log;
/**
@@ -30,8 +32,9 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
private final static Log _log = new Log(TunnelCreateMessage.class);
public final static int MESSAGE_TYPE = 6;
private int _participantType;
private Hash _nextRouter;
private TunnelId _tunnelId;
private Hash _nextRouter;
private TunnelId _nextTunnelId;
private long _tunnelDuration;
private TunnelConfigurationSessionKey _configKey;
private long _maxPeakMessagesPerMin;
@@ -44,7 +47,10 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
private TunnelSigningPrivateKey _verificationPrivKey;
private TunnelSessionKey _tunnelKey;
private Certificate _certificate;
private SourceRouteBlock _replyBlock;
private SessionTag _replyTag;
private SessionKey _replyKey;
private TunnelId _replyTunnel;
private Hash _replyPeer;
public static final int PARTICIPANT_TYPE_GATEWAY = 1;
public static final int PARTICIPANT_TYPE_ENDPOINT = 2;
@@ -57,6 +63,7 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
super(context);
setParticipantType(-1);
setNextRouter(null);
setNextTunnelId(null);
setTunnelId(null);
setTunnelDurationSeconds(-1);
setConfigurationKey(null);
@@ -70,13 +77,18 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
setVerificationPrivateKey(null);
setTunnelKey(null);
setCertificate(null);
setReplyBlock(null);
setReplyTag(null);
setReplyKey(null);
setReplyTunnel(null);
setReplyPeer(null);
}
public void setParticipantType(int type) { _participantType = type; }
public int getParticipantType() { return _participantType; }
public void setNextRouter(Hash routerIdentityHash) { _nextRouter = routerIdentityHash; }
public Hash getNextRouter() { return _nextRouter; }
public void setNextTunnelId(TunnelId id) { _nextTunnelId = id; }
public TunnelId getNextTunnelId() { return _nextTunnelId; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelDurationSeconds(long durationSeconds) { _tunnelDuration = durationSeconds; }
@@ -103,8 +115,14 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
public TunnelSessionKey getTunnelKey() { return _tunnelKey; }
public void setCertificate(Certificate cert) { _certificate = cert; }
public Certificate getCertificate() { return _certificate; }
public void setReplyBlock(SourceRouteBlock block) { _replyBlock = block; }
public SourceRouteBlock getReplyBlock() { return _replyBlock; }
public void setReplyTag(SessionTag tag) { _replyTag = tag; }
public SessionTag getReplyTag() { return _replyTag; }
public void setReplyKey(SessionKey key) { _replyKey = key; }
public SessionKey getReplyKey() { return _replyKey; }
public void setReplyTunnel(TunnelId id) { _replyTunnel = id; }
public TunnelId getReplyTunnel() { return _replyTunnel; }
public void setReplyPeer(Hash peer) { _replyPeer = peer; }
public Hash getReplyPeer() { return _replyPeer; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
@@ -113,6 +131,8 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter = new Hash();
_nextRouter.readBytes(in);
_nextTunnelId = new TunnelId();
_nextTunnelId.readBytes(in);
}
_tunnelId = new TunnelId();
_tunnelId.readBytes(in);
@@ -140,8 +160,14 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
}
_certificate = new Certificate();
_certificate.readBytes(in);
_replyBlock = new SourceRouteBlock();
_replyBlock.readBytes(in);
_replyTag = new SessionTag();
_replyTag.readBytes(in);
_replyKey = new SessionKey();
_replyKey.readBytes(in);
_replyTunnel = new TunnelId();
_replyTunnel.readBytes(in);
_replyPeer = new Hash();
_replyPeer.readBytes(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
@@ -153,6 +179,7 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
DataHelper.writeLong(os, 1, _participantType);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter.writeBytes(os);
_nextTunnelId.writeBytes(os);
}
_tunnelId.writeBytes(os);
DataHelper.writeLong(os, 4, _tunnelDuration);
@@ -174,7 +201,10 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
_tunnelKey.writeBytes(os);
}
_certificate.writeBytes(os);
_replyBlock.writeBytes(os);
_replyTag.writeBytes(os);
_replyKey.writeBytes(os);
_replyTunnel.writeBytes(os);
_replyPeer.writeBytes(os);
} catch (Throwable t) {
throw new I2NPMessageException("Error writing out the message data", t);
}
@@ -201,21 +231,23 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
public int hashCode() {
return (int)(DataHelper.hashCode(getCertificate()) +
DataHelper.hashCode(getConfigurationKey()) +
DataHelper.hashCode(getNextRouter()) +
DataHelper.hashCode(getReplyBlock()) +
DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(getTunnelKey()) +
DataHelper.hashCode(getVerificationPrivateKey()) +
DataHelper.hashCode(getVerificationPublicKey()) +
(getIncludeDummyTraffic() ? 1 : 0) +
getMaxAvgBytesPerMin() +
getMaxAvgMessagesPerMin() +
getMaxPeakBytesPerMin() +
getMaxPeakMessagesPerMin() +
getParticipantType() +
(getReorderMessages() ? 1 : 0) +
getTunnelDurationSeconds());
DataHelper.hashCode(getConfigurationKey()) +
DataHelper.hashCode(getNextRouter()) +
DataHelper.hashCode(getNextTunnelId()) +
DataHelper.hashCode(getReplyPeer()) +
DataHelper.hashCode(getReplyTunnel()) +
DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(getTunnelKey()) +
DataHelper.hashCode(getVerificationPrivateKey()) +
DataHelper.hashCode(getVerificationPublicKey()) +
(getIncludeDummyTraffic() ? 1 : 0) +
getMaxAvgBytesPerMin() +
getMaxAvgMessagesPerMin() +
getMaxPeakBytesPerMin() +
getMaxPeakMessagesPerMin() +
getParticipantType() +
(getReorderMessages() ? 1 : 0) +
getTunnelDurationSeconds());
}
public boolean equals(Object object) {
@@ -224,7 +256,11 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
return DataHelper.eq(getCertificate(), msg.getCertificate()) &&
DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) &&
DataHelper.eq(getNextRouter(), msg.getNextRouter()) &&
DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) &&
DataHelper.eq(getNextTunnelId(), msg.getNextTunnelId()) &&
DataHelper.eq(getReplyTag(), msg.getReplyTag()) &&
DataHelper.eq(getReplyKey(), msg.getReplyKey()) &&
DataHelper.eq(getReplyTunnel(), msg.getReplyTunnel()) &&
DataHelper.eq(getReplyPeer(), msg.getReplyPeer()) &&
DataHelper.eq(getTunnelId(), msg.getTunnelId()) &&
DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) &&
DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) &&
@@ -249,7 +285,11 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
buf.append("\n\tCertificate: ").append(getCertificate());
buf.append("\n\tConfiguration Key: ").append(getConfigurationKey());
buf.append("\n\tNext Router: ").append(getNextRouter());
buf.append("\n\tReply Block: ").append(getReplyBlock());
buf.append("\n\tNext Tunnel: ").append(getNextTunnelId());
buf.append("\n\tReply Tag: ").append(getReplyTag());
buf.append("\n\tReply Key: ").append(getReplyKey());
buf.append("\n\tReply Tunnel: ").append(getReplyTunnel());
buf.append("\n\tReply Peer: ").append(getReplyPeer());
buf.append("\n\tTunnel ID: ").append(getTunnelId());
buf.append("\n\tTunnel Key: ").append(getTunnelKey());
buf.append("\n\tVerification Private Key: ").append(getVerificationPrivateKey());