package net.i2p.data.i2cp; /* * Released into the public domain * with no warranty of any kind, either expressed or implied. * */ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; /** * Response to HostLookupMessage. Replaces DestReplyMessage. * * @since 0.9.11 */ public class HostReplyMessage extends I2CPMessageImpl { public final static int MESSAGE_TYPE = 39; private Destination _dest; private long _reqID; private int _code; private SessionId _sessionId; public static final int RESULT_SUCCESS = 0; /** generic fail, other codes TBD */ public static final int RESULT_FAILURE = 1; private static final long MAX_INT = (1L << 32) - 1; public HostReplyMessage() {} /** * A message with RESULT_SUCCESS and a non-null Destination. * * @param d non-null * @param reqID 0 to 2**32 - 1 */ public HostReplyMessage(SessionId id, Destination d, long reqID) { if (id == null || d == null) throw new IllegalArgumentException(); if (reqID < 0 || reqID > MAX_INT) throw new IllegalArgumentException(); _sessionId = id; _dest = d; _reqID = reqID; } /** * A message with a failure code and no Destination. * * @param failureCode 1-255 * @param reqID from the HostLookup 0 to 2**32 - 1 */ public HostReplyMessage(SessionId id, int failureCode, long reqID) { if (id == null) throw new IllegalArgumentException(); if (failureCode <= 0 || failureCode > 255) throw new IllegalArgumentException(); if (reqID < 0 || reqID > MAX_INT) throw new IllegalArgumentException(); _sessionId = id; _code = failureCode; _reqID = reqID; } public SessionId getSessionId() { return _sessionId; } /** * Return the SessionId for this message. * * @since 0.9.21 */ @Override public SessionId sessionId() { return _sessionId; } /** * @return 0 to 2**32 - 1 */ public long getReqID() { return _reqID; } /** * @return 0 on success, 1-255 on failure */ public int getResultCode() { return _code; } /** * @return non-null only if result code is zero */ public Destination getDestination() { return _dest; } protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException { try { _sessionId = new SessionId(); _sessionId.readBytes(in); _reqID = DataHelper.readLong(in, 4); _code = (int) DataHelper.readLong(in, 1); if (_code == RESULT_SUCCESS) _dest = Destination.create(in); } catch (DataFormatException dfe) { throw new I2CPMessageException("bad data", dfe); } } protected byte[] doWriteMessage() throws I2CPMessageException, IOException { int len = 7; if (_code == RESULT_SUCCESS) { if (_dest == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); len += _dest.size(); } ByteArrayOutputStream os = new ByteArrayOutputStream(len); try { _sessionId.writeBytes(os); DataHelper.writeLong(os, 4, _reqID); DataHelper.writeLong(os, 1, _code); if (_code == RESULT_SUCCESS) _dest.writeBytes(os); } catch (DataFormatException dfe) { throw new I2CPMessageException("bad data", dfe); } return os.toByteArray(); } public int getType() { return MESSAGE_TYPE; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("[HostReplyMessage: "); buf.append("\n\t").append(_sessionId); buf.append("\n\tReqID: ").append(_reqID); buf.append("\n\tResult: ").append(_code); if (_code == RESULT_SUCCESS) buf.append("\n\tDestination: ").append(_dest); buf.append("]"); return buf.toString(); } }