001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.net.protocol.delivery;
006:
007: import com.tc.bytes.TCByteBuffer;
008: import com.tc.net.protocol.AbstractTCNetworkHeader;
009: import com.tc.net.protocol.TCProtocolException;
010:
011: /**
012: * Header for once and only once protocol messages.
013: */
014: class OOOProtocolMessageHeader extends AbstractTCNetworkHeader {
015:
016: public static final short TYPE_HANDSHAKE = 1;
017: public static final short TYPE_HANDSHAKE_REPLY_OK = 2;
018: public static final short TYPE_HANDSHAKE_REPLY_FAIL = 3;
019: public static final short TYPE_ACK = 4;
020: public static final short TYPE_SEND = 5;
021: public static final short TYPE_GOODBYE = 6;
022:
023: public static final String[] typeNames = new String[] { "N/A",
024: "TYPE_HANDSHAKE", "TYPE_HANDSHAKE_REPLY_OK",
025: "TYPE_HANDSHAKE_REPLY_FAIL", "TYPE_ACK", "TYPE_SEND",
026: "TYPE_GOODBYE", };
027:
028: public static final short VERSION = 1;
029:
030: private static final int MAGIC_NUM = 0xBBBBBBBB;
031: private static final int MAGIC_NUM_OFFSET = 0;
032: private static final int MAGIC_NUM_LENGTH = 4;
033:
034: private static final int VERSION_OFFSET = MAGIC_NUM_OFFSET
035: + MAGIC_NUM_LENGTH;
036: private static final int VERSION_LENGTH = 1;
037:
038: private static final int TYPE_OFFSET = VERSION_OFFSET
039: + VERSION_LENGTH;
040: private static final int TYPE_LENGTH = 1;
041:
042: private static final int SEQUENCE_OFFSET = TYPE_OFFSET
043: + TYPE_LENGTH;
044: private static final int SEQUENCE_LENGTH = 8;
045:
046: private static final int SESSION_OFFSET = SEQUENCE_OFFSET
047: + SEQUENCE_LENGTH;
048: private static final int SESSION_LENGTH = 2;
049:
050: static final int HEADER_LENGTH;
051:
052: static {
053: int tmp = MAGIC_NUM_LENGTH + VERSION_LENGTH + TYPE_LENGTH
054: + SEQUENCE_LENGTH + SESSION_LENGTH;
055: // This padding is here to ensure that the header is a multiple of four bytes.
056: HEADER_LENGTH = (tmp + 3) / 4 * 4;
057: }
058:
059: OOOProtocolMessageHeader(short version, short type, long sequence,
060: short sessionId) {
061: super (HEADER_LENGTH, HEADER_LENGTH);
062: putValues(version, type, sequence, sessionId);
063: try {
064: validate();
065: } catch (TCProtocolException e) {
066: throw new InternalError();
067: }
068: }
069:
070: OOOProtocolMessageHeader(TCByteBuffer buffer) {
071: super (buffer, HEADER_LENGTH, HEADER_LENGTH);
072: }
073:
074: public int getHeaderByteLength() {
075: return HEADER_LENGTH;
076: }
077:
078: private void putValues(short version, short type, long sequence,
079: short sessionId) {
080: data.putInt(MAGIC_NUM_OFFSET, MAGIC_NUM);
081: data.putUbyte(VERSION_OFFSET, version);
082: data.putUbyte(TYPE_OFFSET, type);
083: data.putLong(SEQUENCE_OFFSET, sequence);
084: data.putShort(SESSION_OFFSET, sessionId);
085: }
086:
087: protected void setHeaderLength(short headerLength) {
088: throw new UnsupportedOperationException(
089: "These messages are fixed length.");
090: }
091:
092: public void validate() throws TCProtocolException {
093: int magic = getMagicNumber();
094: if (magic != MAGIC_NUM) {
095: throw new TCProtocolException("Bad magic number: " + magic
096: + " != " + MAGIC_NUM);
097: }
098:
099: short version = getVersion();
100: if (getVersion() != VERSION) {
101: throw new TCProtocolException("Reported version " + version
102: + " is not equal to supported version: " + VERSION);
103: }
104: short type = getType();
105: if (!isValidType(type)) {
106: throw new TCProtocolException("Unknown message type: "
107: + type);
108: }
109:
110: final boolean ack = isAck();
111: final boolean ackReq = isHandshake();
112: final boolean send = isSend();
113:
114: if (ack && (ackReq || send)) {
115: throw new TCProtocolException("Invalid type, ack= " + ack
116: + ", ackRe=" + ackReq + ", send=" + send);
117: }
118: }
119:
120: public String toString() {
121: StringBuffer buf = new StringBuffer();
122: buf.append("Type=" + typeNames[getType()]);
123: buf.append(" sessId=" + getSession());
124: buf.append(" seq=" + getSequence());
125: return buf.toString();
126: }
127:
128: private int getMagicNumber() {
129: return data.getInt(MAGIC_NUM_OFFSET);
130: }
131:
132: private short getVersion() {
133: return data.getUbyte(VERSION_OFFSET);
134: }
135:
136: private short getType() {
137: return data.getUbyte(TYPE_OFFSET);
138: }
139:
140: private boolean isValidType(short type) {
141: return type == TYPE_SEND || type == TYPE_HANDSHAKE
142: || type == TYPE_HANDSHAKE_REPLY_OK
143: || type == TYPE_HANDSHAKE_REPLY_FAIL
144: || type == TYPE_ACK || type == TYPE_GOODBYE;
145: }
146:
147: long getSequence() {
148: return data.getLong(SEQUENCE_OFFSET);
149: }
150:
151: short getSession() {
152: return data.getShort(SESSION_OFFSET);
153: }
154:
155: boolean isHandshake() {
156: return getType() == TYPE_HANDSHAKE;
157: }
158:
159: boolean isHandshakeReplyOk() {
160: return getType() == TYPE_HANDSHAKE_REPLY_OK;
161: }
162:
163: boolean isHandshakeReplyFail() {
164: return getType() == TYPE_HANDSHAKE_REPLY_FAIL;
165: }
166:
167: boolean isAck() {
168: return getType() == TYPE_ACK;
169: }
170:
171: boolean isSend() {
172: return getType() == TYPE_SEND;
173: }
174:
175: boolean isGoodbye() {
176: return getType() == TYPE_GOODBYE;
177: }
178:
179: }
|