All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ice4j.attribute.UnknownAttributesAttribute Maven / Gradle / Ivy

There is a newer version: 3.2-4-g1373788
Show newest version
 /*
 * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal.
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ice4j.attribute;

import java.util.*;

import org.ice4j.*;

/**
 * The UNKNOWN-ATTRIBUTES attribute is present only in a Binding Error
 * Response or Shared Secret Error Response when the response code in
 * the ERROR-CODE attribute is 420.
 *
 * The attribute contains a list of 16 bit values, each of which
 * represents an attribute type that was not understood by the server.
 * If the number of unknown attributes is an odd number, one of the
 * attributes MUST be repeated in the list, so that the total length of
 * the list is a multiple of 4 bytes.
 *
 * 0                   1                   2                   3
 * 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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |      Attribute 1 Type           |     Attribute 2 Type        |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |      Attribute 3 Type           |     Attribute 4 Type    ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * @author Emil Ivov
 */
public class UnknownAttributesAttribute extends Attribute
{
    /**
     * Attribute name.
     */
    public static String NAME = "UNKNOWN-ATTRIBUTES";

    /**
     * A list of attribute types that were not understood by the server.
     */
    private ArrayList unknownAttributes = new ArrayList<>();

    /**
     * Constructor.
     */
    UnknownAttributesAttribute()
    {
        super(UNKNOWN_ATTRIBUTES);
    }

    /**
     * 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()
    {
        return NAME;
    }

   /**
    * Returns the length (in bytes) of this attribute's body.
    * If the number of unknown attributes is an odd number, one of the
    * attributes MUST be repeated in the list, so that the total length of
    * the list is a multiple of 4 bytes.
    * @return the length of this attribute's value (a multiple of 4).
    */
    public char getDataLength()
    {
        char len = (char)unknownAttributes.size();

        if ( (len % 2 ) != 0 )
            len++;

        return (char)(len * 2);
    }

    /**
     * Adds the specified attribute type to the list of unknown attributes.
     * @param attributeID the id of an attribute to be listed as unknown in this
     * attribute
     */
    public void addAttributeID(char attributeID)
    {
        //some attributes may be repeated for padding
        //(packet length should be divisable by 4)
        if (!contains(attributeID))
            unknownAttributes.add(attributeID);
    }

    /**
     * Verifies whether the specified attributeID is contained by this attribute.
     * @param attributeID the attribute id to look for.
     * @return true if this attribute contains the specified attribute id.
     */
    public boolean contains(char attributeID)
    {
        return unknownAttributes.contains(attributeID);
    }

    /**
     * Returns an iterator over the list of attribute IDs contained by this
     * attribute.
     * @return an iterator over the list of attribute IDs contained by this
     * attribute.
     */
    public Iterator getAttributes()
    {
        return unknownAttributes.iterator();
    }

    /**
     * Returns the number of attribute IDs contained by this class.
     * @return the number of attribute IDs contained by this class.
     */
    public int getAttributeCount()
    {
        return unknownAttributes.size();
    }

    /**
     * Returns the attribute id with index i.
     * @param index the index of the attribute id to return.
     * @return the attribute id with index i.
     */
    public char getAttribute(int index )
    {
        return unknownAttributes.get(index);
    }

    /**
     * Returns a binary representation of this attribute.
     * @return a binary representation of this attribute.
     */
    public byte[] encode()
    {
        byte binValue[] = new byte[getDataLength() + HEADER_LENGTH];
        int  offset     = 0;

        //Type
        binValue[offset++] = (byte) (getAttributeType() >> 8);
        binValue[offset++] = (byte) (getAttributeType() & 0x00FF);

        //Length
        binValue[offset++] = (byte) (getDataLength() >> 8);
        binValue[offset++] = (byte) (getDataLength() & 0x00FF);


        Iterator attributes = getAttributes();
        while (attributes.hasNext())
        {
            char att = attributes.next();
            binValue[offset++] = (byte)(att >> 8);
            binValue[offset++] = (byte)(att & 0x00FF);
        }

       // If the number of unknown attributes is an odd number, one of the
       // attributes MUST be repeated in the list, so that the total length of
       // the list is a multiple of 4 bytes.
       if (offset < binValue.length)
       {
           char att = getAttribute(0);
           binValue[offset++] = (byte) (att >> 8);
           binValue[offset++] = (byte) (att & 0x00FF);
       }

        return binValue;
    }

    /**
     * Compares two STUN Attributes. Attributes 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 UnknownAttributesAttribute))
            return false;

        if (obj == this)
            return true;

        UnknownAttributesAttribute att = (UnknownAttributesAttribute) obj;
        if (att.getAttributeType() != getAttributeType()
            || att.getDataLength() != getDataLength()
            || !unknownAttributes.equals(att.unknownAttributes)
        )
            return false;

        return true;
    }

    /**
     * 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
    {
        if ( (length % 2 ) != 0)
            throw new StunException("Attribute IDs are 2 bytes long and the "
                                    + "passed binary array has an odd length " +
                                            "value.");
        char originalOffset = offset;
        for (int i = offset; i < originalOffset + length; i += 2)
        {
            char attributeID = (char) (((attributeValue[offset++] & 0xFF) << 8)
                | (attributeValue[offset++] & 0xFF));
            addAttributeID(attributeID);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy