172 lines
6.5 KiB
Java
172 lines
6.5 KiB
Java
![]() |
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.InputStream;
|
||
|
import java.io.OutputStream;
|
||
|
import java.io.IOException;
|
||
|
|
||
|
import net.i2p.util.Log;
|
||
|
|
||
|
import net.i2p.data.DataHelper;
|
||
|
import net.i2p.data.DataStructureImpl;
|
||
|
import net.i2p.data.DataFormatException;
|
||
|
import net.i2p.data.Certificate;
|
||
|
|
||
|
import java.util.Date;
|
||
|
|
||
|
/**
|
||
|
* Contains one deliverable message encrypted to a router along with instructions
|
||
|
* and a certificate 'paying for' the delivery.
|
||
|
*
|
||
|
* @author jrandom
|
||
|
*/
|
||
|
public class GarlicClove extends DataStructureImpl {
|
||
|
private final static Log _log = new Log(GarlicClove.class);
|
||
|
private DeliveryInstructions _instructions;
|
||
|
private I2NPMessage _msg;
|
||
|
private long _cloveId;
|
||
|
private Date _expiration;
|
||
|
private Certificate _certificate;
|
||
|
private int _replyAction;
|
||
|
private SourceRouteBlock _sourceRouteBlock;
|
||
|
|
||
|
/** 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() {
|
||
|
setInstructions(null);
|
||
|
setData(null);
|
||
|
setCloveId(-1);
|
||
|
setExpiration(null);
|
||
|
setCertificate(null);
|
||
|
setSourceRouteBlockAction(ACTION_NONE);
|
||
|
setSourceRouteBlock(null);
|
||
|
}
|
||
|
|
||
|
public DeliveryInstructions getInstructions() { return _instructions; }
|
||
|
public void setInstructions(DeliveryInstructions instr) { _instructions = instr; }
|
||
|
public I2NPMessage getData() { return _msg; }
|
||
|
public void setData(I2NPMessage msg) { _msg = msg; }
|
||
|
public long getCloveId() { return _cloveId; }
|
||
|
public void setCloveId(long id) { _cloveId = id; }
|
||
|
public Date getExpiration() { return _expiration; }
|
||
|
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();
|
||
|
_instructions.readBytes(in);
|
||
|
_log.debug("Read instructions: " + _instructions);
|
||
|
try {
|
||
|
_msg = new I2NPMessageHandler().readMessage(in);
|
||
|
} catch (I2NPMessageException ime) {
|
||
|
throw new DataFormatException("Unable to read the message from a garlic clove", ime);
|
||
|
}
|
||
|
_cloveId = DataHelper.readLong(in, 4);
|
||
|
_expiration = DataHelper.readDate(in);
|
||
|
_log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration);
|
||
|
_certificate = new Certificate();
|
||
|
_certificate.readBytes(in);
|
||
|
_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 {
|
||
|
StringBuffer error = new StringBuffer();
|
||
|
if (_instructions == null)
|
||
|
error.append("No instructions ");
|
||
|
if (_msg == null)
|
||
|
error.append("No message ");
|
||
|
if (_cloveId < 0)
|
||
|
error.append("CloveID < 0 [").append(_cloveId).append("] ");
|
||
|
if (_expiration == null)
|
||
|
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);
|
||
|
|
||
|
_log.debug("Wrote instructions: " + _instructions);
|
||
|
_msg.writeBytes(out);
|
||
|
DataHelper.writeLong(out, 4, _cloveId);
|
||
|
DataHelper.writeDate(out, _expiration);
|
||
|
_log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration);
|
||
|
_certificate.writeBytes(out);
|
||
|
_log.debug("Written cert: " + _certificate);
|
||
|
DataHelper.writeLong(out, 1, _replyAction);
|
||
|
if ( (_replyAction != 0) && (_sourceRouteBlock != null) )
|
||
|
_sourceRouteBlock.writeBytes(out);
|
||
|
}
|
||
|
|
||
|
public boolean equals(Object obj) {
|
||
|
if ( (obj == null) || !(obj instanceof GarlicClove))
|
||
|
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());
|
||
|
}
|
||
|
|
||
|
public int hashCode() {
|
||
|
return DataHelper.hashCode(getCertificate()) +
|
||
|
(int)getCloveId() +
|
||
|
DataHelper.hashCode(getData()) +
|
||
|
DataHelper.hashCode(getExpiration()) +
|
||
|
DataHelper.hashCode(getInstructions()) +
|
||
|
DataHelper.hashCode(getSourceRouteBlock()) +
|
||
|
getSourceRouteBlockAction();
|
||
|
}
|
||
|
|
||
|
public String toString() {
|
||
|
StringBuffer buf = new StringBuffer(128);
|
||
|
buf.append("[GarlicClove: ");
|
||
|
buf.append("\n\tInstructions: ").append(getInstructions());
|
||
|
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();
|
||
|
}
|
||
|
}
|