📄 message.java
字号:
public void setTransactionID(byte[] tranID)
throws StunException
{
if(tranID == null
|| tranID.length != TRANSACTION_ID_LENGTH)
throw new StunException(StunException.ILLEGAL_ARGUMENT,
"Invalid transaction id");
this.transactionID = new byte[TRANSACTION_ID_LENGTH];
System.arraycopy(tranID, 0,
this.transactionID, 0, TRANSACTION_ID_LENGTH);
}
/**
* Returns a reference to this message's transaction id.
* @return a reference to this message's transaction id.
*/
public byte[] getTransactionID()
{
return this.transactionID;
}
/**
* Returns whether an attribute could be present in this message.
* @param attributeType the id of the attribute to check .
* @return Message.N_A - for not applicable <br/>
* Message.C - for case depending <br/>
* Message.N_A - for not applicable <br/>
*/
protected byte getAttributePresentity(char attributeType)
{
byte msgIndex = -1;
byte attributeIndex = -1;
switch (messageType)
{
case BINDING_REQUEST: msgIndex = BINDING_REQUEST_PRESENTITY_INDEX; break;
case BINDING_RESPONSE: msgIndex = BINDING_RESPONSE_PRESENTITY_INDEX; break;
case BINDING_ERROR_RESPONSE: msgIndex = BINDING_ERROR_RESPONSE_PRESENTITY_INDEX; break;
case SHARED_SECRET_REQUEST: msgIndex = SHARED_SECRET_REQUEST_PRESENTITY_INDEX; break;
case SHARED_SECRET_RESPONSE: msgIndex = SHARED_SECRET_RESPONSE_PRESENTITY_INDEX; break;
case SHARED_SECRET_ERROR_RESPONSE: msgIndex = SHARED_SECRET_ERROR_RESPONSE_PRESENTITY_INDEX; break;
}
switch (attributeType)
{
case Attribute.MAPPED_ADDRESS: attributeIndex = MAPPED_ADDRESS_PRESENTITY_INDEX; break;
case Attribute.RESPONSE_ADDRESS: attributeIndex = RESPONSE_ADDRESS_PRESENTITY_INDEX; break;
case Attribute.CHANGE_REQUEST: attributeIndex = CHANGE_REQUEST_PRESENTITY_INDEX; break;
case Attribute.SOURCE_ADDRESS: attributeIndex = SOURCE_ADDRESS_PRESENTITY_INDEX; break;
case Attribute.CHANGED_ADDRESS: attributeIndex = CHANGED_ADDRESS_PRESENTITY_INDEX; break;
case Attribute.USERNAME: attributeIndex = USERNAME_PRESENTITY_INDEX; break;
case Attribute.PASSWORD: attributeIndex = PASSWORD_PRESENTITY_INDEX; break;
case Attribute.MESSAGE_INTEGRITY: attributeIndex = MESSAGE_INTEGRITY_PRESENTITY_INDEX; break;
case Attribute.ERROR_CODE: attributeIndex = ERROR_CODE_PRESENTITY_INDEX; break;
case Attribute.UNKNOWN_ATTRIBUTES: attributeIndex = UNKNOWN_ATTRIBUTES_PRESENTITY_INDEX; break;
case Attribute.REFLECTED_FROM: attributeIndex = REFLECTED_FROM_PRESENTITY_INDEX; break;
case Attribute.XOR_MAPPED_ADDRESS: attributeIndex = XOR_MAPPED_ADDRESS_PRESENTITY_INDEX; break;
case Attribute.XOR_ONLY: attributeIndex = XOR_ONLY_PRESENTITY_INDEX; break;
case Attribute.SERVER: attributeIndex = SERVER_PRESENTITY_INDEX; break;
default: attributeIndex = UNKNOWN_OPTIONAL_ATTRIBUTES_PRESENTITY_INDEX; break;
}
return attributePresentities[ attributeIndex ][ msgIndex ];
}
/**
* Returns the human readable name of this message. Message names do
* not really matter from the protocol point of view. They are only used
* for debugging and readability.
* @return this message's name.
*/
public String getName()
{
switch (messageType)
{
case BINDING_REQUEST: return "BINDING-REQUEST";
case BINDING_RESPONSE: return "BINDING-RESPONSE";
case BINDING_ERROR_RESPONSE: return "BINDING-ERROR-RESPONSE";
case SHARED_SECRET_REQUEST: return "SHARED-SECRET-REQUEST";
case SHARED_SECRET_RESPONSE: return "SHARED-SECRET-RESPONSE";
case SHARED_SECRET_ERROR_RESPONSE: return "SHARED-SECRET-ERROR-RESPONSE";
}
return "UNKNOWN-MESSAGE";
}
/**
* Compares two STUN Messages. Messages are considered equal when their
* type, length, and all their attributes are equal.
*
* @param obj the object to compare this message with.
* @return true if the messages are equal and false otherwise.
*/
public boolean equals(Object obj)
{
if(!(obj instanceof Message)
|| obj == null)
return false;
if(obj == this)
return true;
Message msg = (Message) obj;
if( msg.getMessageType() != getMessageType())
return false;
if(msg.getDataLength() != getDataLength())
return false;
//compare attributes
Iterator iter = attributes.entrySet().iterator();
while (iter.hasNext()) {
Attribute localAtt = (Attribute)((Map.Entry)iter.next()).getValue();
if(!localAtt.equals(msg.getAttribute(localAtt.getAttributeType())))
return false;
}
return true;
}
/**
* Returns a binary representation of this message.
* @return a binary representation of this message.
* @throws StunException if the message does not have all required
* attributes.
*/
public byte[] encode()
throws StunException
{
//make sure we have everything necessary to encode a proper message
validateAttributePresentity();
char dataLength = getDataLength();
byte binMsg[] = new byte[HEADER_LENGTH + dataLength];
int offset = 0;
binMsg[offset++] = (byte)(getMessageType()>>8);
binMsg[offset++] = (byte)(getMessageType()&0xFF);
binMsg[offset++] = (byte)(dataLength >> 8);
binMsg[offset++] = (byte)(dataLength & 0xFF);
System.arraycopy(getTransactionID(), 0, binMsg, offset, TRANSACTION_ID_LENGTH);
offset+=TRANSACTION_ID_LENGTH;
Iterator iter = attributes.entrySet().iterator();
while (iter.hasNext()) {
Attribute attribute = (Attribute)((Map.Entry)iter.next()).getValue();
byte[] attBinValue = attribute.encode();
System.arraycopy(attBinValue, 0, binMsg, offset, attBinValue.length);
offset += attBinValue.length;
}
return binMsg;
}
/**
* Constructs a message from its binary representation.
* @param binMessage the binary array that contains the encoded message
* @param offset the index where the message starts.
* @param arrayLen the length of the message
* @return a Message object constructed from the binMessage array
* @throws StunException ILLEGAL_ARGUMENT if one or more of the arguments
* have invalid values.
*/
public static Message decode(byte binMessage[], char offset, char arrayLen)
throws StunException
{
arrayLen = (char)Math.min(binMessage.length, arrayLen);
if(binMessage == null || arrayLen - offset < Message.HEADER_LENGTH)
throw new StunException(StunException.ILLEGAL_ARGUMENT,
"The given binary array is not a valid StunMessage");
char messageType = (char)((binMessage[offset++]<<8) | (binMessage[offset++]&0xFF));
Message message;
if (Message.isResponseType(messageType))
{
message = new Response();
}
else
{
message = new Request();
}
message.setMessageType(messageType);
int length = (char)((binMessage[offset++]<<8) | (binMessage[offset++]&0xFF));
if(arrayLen - offset - TRANSACTION_ID_LENGTH < length)
throw new StunException(StunException.ILLEGAL_ARGUMENT,
"The given binary array does not seem to "
+"contain a whole StunMessage");
byte tranID[] = new byte[TRANSACTION_ID_LENGTH];
System.arraycopy(binMessage, offset, tranID, 0, TRANSACTION_ID_LENGTH);
message.setTransactionID(tranID);
offset+=TRANSACTION_ID_LENGTH;
while(offset - Message.HEADER_LENGTH< length)
{
Attribute att = AttributeDecoder.decode(binMessage,
(char)offset,
(char)(length - offset));
message.addAttribute(att);
offset += att.getDataLength() + Attribute.HEADER_LENGTH;
}
return message;
}
/**
* Verify that the message has all obligatory attributes and throw an
* exception if this is not the case.
*
* @return true if the message has all obligatory attributes, false
* otherwise.
* @throws StunException (ILLEGAL_STATE)if the message does not have all
* required attributes.
*/
protected void validateAttributePresentity()
throws StunException
{
for(char i = Attribute.MAPPED_ADDRESS; i < Attribute.REFLECTED_FROM; i++)
if(getAttributePresentity(i) == M && getAttribute(i) == null)
throw new StunException(StunException.ILLEGAL_STATE,
"A mandatory attribute (type="
+(int)i
+ ") is missing!");
}
/**
* Determines whether type could be the type of a STUN Response (as opposed
* to STUN Request).
* @param type the type to test.
* @return true if type is a valid response type.
*/
public static boolean isResponseType(char type)
{
return (((type >> 8) & 1) != 0);
}
/**
* Determines whether type could be the type of a STUN Request (as opposed
* to STUN Response).
* @param type the type to test.
* @return true if type is a valid request type.
*/
public static boolean isRequestType(char type)
{
return !isResponseType(type);
}
public String toString()
{
return getName()+"("+getMessageType()
+")[attrib.count=" + getAttributeCount()
+" len=" + this.getDataLength()
+" tranID=" + this.getTransactionID() + "]";
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -