package net.i2p.data.i2cp; /* * 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.IOException; import java.io.InputStream; import java.io.OutputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; /** * Defines the message a router sends to a client about a single message. * For incoming messages, it tells the client that a new message is available. * For outgoing messages, it tells the client whether the message was delivered. * * @author jrandom */ public class MessageStatusMessage extends I2CPMessageImpl { public final static int MESSAGE_TYPE = 22; private int _sessionId; private long _messageId; private long _nonce; private long _size; private int _status; /** * For incoming messages. All the rest are for outgoing. */ public final static int STATUS_AVAILABLE = 0; public final static int STATUS_SEND_ACCEPTED = 1; /** unused */ public final static int STATUS_SEND_BEST_EFFORT_SUCCESS = 2; /** * A probable failure, but we don't know for sure. */ public final static int STATUS_SEND_BEST_EFFORT_FAILURE = 3; /** * Generic success. * May not really be guaranteed, as the best-effort * success code is unused. */ public final static int STATUS_SEND_GUARANTEED_SUCCESS = 4; /** * Generic failure, specific cause unknown. * May not really be a guaranteed failure, as the best-effort * failure code is unused. */ public final static int STATUS_SEND_GUARANTEED_FAILURE = 5; /** * The far-end destination is local and we are pretty darn sure * the delivery succeeded. * @since 0.9.5 */ public final static int STATUS_SEND_SUCCESS_LOCAL = 6; /** * The far-end destination is local but delivery failed for some reason. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_LOCAL = 7; /** * The router is not ready, has shut down, or has major problems. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_ROUTER = 8; /** * The PC apparently has no network connectivity at all. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_NETWORK = 9; /** * The session is invalid or closed. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_BAD_SESSION = 10; /** * The message payload is invalid or zero-length or too big. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_BAD_MESSAGE = 11; /** * Something is invalid in the message options, or the expiration * is too far in the future. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_BAD_OPTIONS = 12; /** * Some queue or buffer in the router is full and the message was dropped. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_OVERFLOW = 13; /** * Message expired before it could be sent. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_EXPIRED = 14; /** * Local leaseset problems. The client has not yet signed * a leaseset, or the local keys are invalid, or it has expired, * or it does not have any tunnels in it. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_LOCAL_LEASESET = 15; /** * Local problems - no outbound tunnel to send through, * or no inbound tunnel if a reply is required. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_NO_TUNNELS = 16; /** * The certs or options in the destination or leaseset indicate that * it uses an encryption format that we don't support, so we can't talk to it. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION = 17; /** * Something strange is wrong with the far-end destination. * Bad format, unsupported options, certificates, etc. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_DESTINATION = 18; /** * We got the far-end leaseset but something strange is wrong with it. * Unsupported options or certificates, no tunnels, etc. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_BAD_LEASESET = 19; /** * We got the far-end leaseset but it's expired and can't get a new one. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_EXPIRED_LEASESET = 20; /** * Could not find the far-end destination's lease set. * This is a common failure, equivalent to a DNS lookup fail. * This is a guaranteed failure. * @since 0.9.5 */ public final static int STATUS_SEND_FAILURE_NO_LEASESET = 21; public MessageStatusMessage() { _sessionId = -1; _status = -1; _messageId = -1; _size = -1; _nonce = -1; } public long getSessionId() { return _sessionId; } /** * Return the SessionId for this message. * * @since 0.9.21 */ @Override public SessionId sessionId() { return _sessionId >= 0 ? new SessionId(_sessionId) : null; } /** @param id 0-65535 */ public void setSessionId(long id) { _sessionId = (int) id; } public int getStatus() { return _status; } /** @param status 0-255 */ public void setStatus(int status) { _status = status; } /** * Is the status code a success status code? * @since 0.9.5 */ public boolean isSuccessful() { return isSuccessful(_status); } /** * Is the status code a success status code? * @since 0.9.5 */ public static boolean isSuccessful(int status) { return status == STATUS_SEND_GUARANTEED_SUCCESS || status == STATUS_SEND_BEST_EFFORT_SUCCESS || status == STATUS_SEND_SUCCESS_LOCAL || status == STATUS_SEND_ACCEPTED || status == STATUS_AVAILABLE; } /** * This is the router's ID for the message */ public long getMessageId() { return _messageId; } /** * This is the router's ID for the message */ public void setMessageId(long id) { _messageId = id; } public long getSize() { return _size; } public void setSize(long size) { _size = size; } /** * This is the client's ID for the message */ public long getNonce() { return _nonce; } /** * This is the client's ID for the message */ public void setNonce(long nonce) { _nonce = nonce; } public static final String getStatusString(int status) { switch (status) { case STATUS_AVAILABLE: return "AVAILABLE "; case STATUS_SEND_ACCEPTED: return "SEND ACCEPTED "; case STATUS_SEND_BEST_EFFORT_SUCCESS: return "BEST EFFORT SUCCESS"; case STATUS_SEND_GUARANTEED_SUCCESS: return "GUARANTEED SUCCESS "; case STATUS_SEND_SUCCESS_LOCAL: return "LOCAL SUCCESS "; case STATUS_SEND_BEST_EFFORT_FAILURE: return "PROBABLE FAILURE "; case STATUS_SEND_FAILURE_NO_TUNNELS: return "NO LOCAL TUNNELS "; case STATUS_SEND_FAILURE_NO_LEASESET: return "LEASESET NOT FOUND "; default: return "SEND FAILURE CODE: " + status; } } @Override protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException { try { _sessionId = (int) DataHelper.readLong(in, 2); _messageId = DataHelper.readLong(in, 4); _status = (int) DataHelper.readLong(in, 1); _size = DataHelper.readLong(in, 4); _nonce = DataHelper.readLong(in, 4); } catch (DataFormatException dfe) { throw new I2CPMessageException("Unable to load the message data", dfe); } } /** * Override to reduce mem churn * @throws IOException */ @Override public void writeMessage(OutputStream out) throws I2CPMessageException, IOException { int len = 2 + // sessionId 4 + // messageId 1 + // status 4 + // size 4; // nonce try { DataHelper.writeLong(out, 4, len); out.write((byte) MESSAGE_TYPE); DataHelper.writeLong(out, 2, _sessionId); DataHelper.writeLong(out, 4, _messageId); out.write((byte) _status); DataHelper.writeLong(out, 4, _size); DataHelper.writeLong(out, 4, _nonce); } catch (DataFormatException dfe) { throw new I2CPMessageException("Unable to write the message length or type", dfe); } } @Override protected byte[] doWriteMessage() throws I2CPMessageException, IOException { throw new UnsupportedOperationException("This shouldn't be called... use writeMessage(out)"); } public int getType() { return MESSAGE_TYPE; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("[MessageStatusMessage: "); buf.append("\n\tSessionId: ").append(_sessionId); buf.append("\n\tNonce: ").append(_nonce); buf.append("\n\tMessageId: ").append(_messageId); buf.append("\n\tStatus: ").append(getStatusString(_status)); buf.append("\n\tSize: ").append(_size); buf.append("]"); return buf.toString(); } }