📄 addressattribute.java
字号:
/*
* Stun4j, the OpenSource Java Solution for NAT and Firewall Traversal.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.stun4j.attribute;
import net.java.stun4j.StunException;
import net.java.stun4j.StunAddress;
import java.util.Arrays;
import java.net.*;
/**
* This class is used to represent Stun attributes that contain an address. Such
* attributes are:
*
* MAPPED-ADDRESS <br/>
* RESPONSE-ADDRESS <br/>
* SOURCE-ADDRESS <br/>
* CHANGED-ADDRESS <br/>
* REFLECTED-FROM <br/>
*
* The different attributes are distinguished by the attributeType of
* net.java.stun4j.attribute.Attribute.
*
* Address attributes indicate the mapped IP address and
* port. They consist of an eight bit address family, and a sixteen bit
* port, followed by a fixed length value representing the IP address.
*
* 0 1 2 3 <br/>
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 <br/>
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <br/>
* |x x x x x x x x| Family | Port | <br/>
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <br/>
* | Address | <br/>
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <br/>
* <br/>
* The port is a network byte ordered representation of the mapped port.
* The address family is always 0x01, corresponding to IPv4. The first
* 8 bits of the MAPPED-ADDRESS are ignored, for the purposes of
* aligning parameters on natural boundaries. The IPv4 address is 32
* bits.
*
*
* <p>Organisation: Louis Pasteur University, Strasbourg, France</p>
* <p>Network Research Team (http://www-r2.u-strasbg.fr)</p></p>
* @author Emil Ivov
* @version 0.1
*/
abstract class AddressAttribute extends Attribute
{
static final byte ADDRESS_FAMILY_IPV4 = 0x01;
static final byte ADDRESS_FAMILY_IPV6 = 0x02;
/**
* The address represented by this message;
*/
protected StunAddress address = null;
/**
* The length of the data contained by this attribute in the case of an
* IPv6 address.
*/
private static final char DATA_LENGTH_FOR_IPV6 = 20;
/**
* The length of the data contained by this attribute in the case of an
* IPv4 address.
*/
private static final char DATA_LENGTH_FOR_IPV4 = 8;
/**
* Constructs an address attribute with the specified type.
*
* @param attributeType the type of the address attribute.
*/
AddressAttribute(char attributeType)
{
super(attributeType);
}
/**
* Verifies that type is a valid address attribute type.
* @param type the type to test
* @return true if the type is a valid address attribute type and false
* otherwise
*/
private boolean isTypeValid(char type)
{
return (type == MAPPED_ADDRESS || type == RESPONSE_ADDRESS
|| type == SOURCE_ADDRESS || type == CHANGED_ADDRESS
|| type == REFLECTED_FROM || type == XOR_MAPPED_ADDRESS);
}
/**
* Sets it as this attribute's type.
*
* @param type the new type of the attribute.
*/
protected void setAttributeType(char type)
{
if (!isTypeValid(type))
throw new IllegalArgumentException(((int)type) + "is not a valid address attribute!");
super.setAttributeType(type);
}
/**
* Returns the human readable name of this attribute. Attribute names do
* not really matter from the protocol point of view. They are only used
* for debugging and readability.
* @return this attribute's name.
*/
public String getName()
{
switch(getAttributeType())
{
case MAPPED_ADDRESS: return MappedAddressAttribute.NAME;
case RESPONSE_ADDRESS: return ResponseAddressAttribute.NAME;
case SOURCE_ADDRESS: return SourceAddressAttribute.NAME;
case CHANGED_ADDRESS: return ChangedAddressAttribute.NAME;
case REFLECTED_FROM: return ReflectedFromAttribute.NAME;
case XOR_MAPPED_ADDRESS: return XorMappedAddressAttribute.NAME;
}
return "UNKNOWN ATTRIBUTE";
}
/**
* Compares two STUN Attributes. Attributeas are considered equal when their
* type, length, and all data are the same.
*
* @param obj the object to compare this attribute with.
* @return true if the attributes are equal and false otherwise.
*/
public boolean equals(Object obj)
{
if (! (obj instanceof AddressAttribute)
|| obj == null)
return false;
if (obj == this)
return true;
AddressAttribute att = (AddressAttribute) obj;
if (att.getAttributeType() != getAttributeType()
|| att.getDataLength() != getDataLength()
//compare data
|| att.getFamily() != getFamily()
|| (att.getAddress() != null
&& !address.equals(att.getAddress()))
)
return false;
//addresses
if( att.getAddress() == null && getAddress() == null)
return true;
return true;
}
/**
* Returns the length of this attribute's body.
* @return the length of this attribute's value (8 bytes).
*/
public char getDataLength()
{
if (getFamily() == ADDRESS_FAMILY_IPV6)
return DATA_LENGTH_FOR_IPV6;
else
return DATA_LENGTH_FOR_IPV4;
}
/**
* Returns a binary representation of this attribute.
* @return a binary representation of this attribute.
*/
public byte[] encode()
{
char type = getAttributeType();
if (!isTypeValid(type))
throw new IllegalStateException(((int)type) + "is not a valid address attribute!");
byte binValue[] = new byte[HEADER_LENGTH + getDataLength()];
//Type
binValue[0] = (byte)(type>>8);
binValue[1] = (byte)(type&0x00FF);
//Length
binValue[2] = (byte)(getDataLength()>>8);
binValue[3] = (byte)(getDataLength()&0x00FF);
//Not used
binValue[4] = 0x00;
//Family
binValue[5] = getFamily();
//port
binValue[6] = (byte)(getPort()>>8);
binValue[7] = (byte)(getPort()&0x00FF);
//address
if(getFamily() == ADDRESS_FAMILY_IPV6){
System.arraycopy(getAddressBytes(), 0, binValue, 8, 16);
}
else{
System.arraycopy(getAddressBytes(), 0, binValue, 8, 4);
}
return binValue;
}
/**
* Sets address to be the address transported by this attribute.
* @param address that this attribute should encapsulate.
*/
public void setAddress(StunAddress address)
{
this.address = address;
}
/**
* Returns the address encapsulated by this attribute.
* @return the address encapsulated by this attribute.
*/
public StunAddress getAddress()
{
return address;
}
public byte[] getAddressBytes()
{
return address.getAddressBytes();
}
/**
* Returns the family that the this.address belongs to.
* @return the family that the this.address belongs to.
*/
public byte getFamily()
{
if ( address.getSocketAddress().getAddress() instanceof Inet6Address )
return ADDRESS_FAMILY_IPV6;
else
return ADDRESS_FAMILY_IPV4;
}
/**
* Returns the port associated with the address contained by the attribute.
* @return the port associated with the address contained by the attribute.
*/
public char getPort()
{
return address.getPort();
}
/**
* Sets this attribute's fields according to attributeValue array.
*
* @param attributeValue a binary array containing this attribute's field
* values and NOT containing the attribute header.
* @param offset the position where attribute values begin (most often
* offset is equal to the index of the first byte after
* length)
* @param length the length of the binary array.
* @throws StunException if attrubteValue contains invalid data.
*/
void decodeAttributeBody(byte[] attributeValue, char offset, char length)
throws StunException
{
//skip through padding
offset ++;
//get family
byte family = attributeValue[offset++];
//port
char port = ((char)((attributeValue[offset++] << 8 ) | (attributeValue[offset++]&0xFF) ));
//address
byte address[] = null;
if(family == ADDRESS_FAMILY_IPV6){
address = new byte[16];
}
else{
//ipv4
address = new byte[4];
}
System.arraycopy(attributeValue, offset, address, 0, address.length);
setAddress(new StunAddress(address, port));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -