⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 errorcodeattribute.java

📁 stun的java实现
💻 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 java.util.Hashtable;
import net.java.stun4j.StunException;

/**
 * The ERROR-CODE attribute is present in the Binding Error Response and
 * Shared Secret Error Response.  It is a numeric value in the range of
 * 100 to 699 plus a textual reason phrase encoded in UTF-8, and is
 * consistent in its code assignments and semantics with SIP [10] and
 * HTTP [15].  The reason phrase is meant for user consumption, and can
 * be anything appropriate for the response code.  The lengths of the
 * reason phrases MUST be a multiple of 4 (measured in bytes).  This can
 * be accomplished by added spaces to the end of the text, if necessary.
 * Recommended reason phrases for the defined response codes are
 * presented below.
 *
 * To facilitate processing, the class of the error code (the hundreds
 * digit) is encoded separately from the rest of the code.
 *
 *   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
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                   0                     |Class|     Number    |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |      Reason Phrase (variable)                                ..
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * The class represents the hundreds digit of the response code.  The
 * value MUST be between 1 and 6.  The number represents the response
 * code modulo 100, and its value MUST be between 0 and 99.
 *
 * The following response codes, along with their recommended reason
 * phrases (in brackets) are defined at this time:
 *
 * 400 (Bad Request): The request was malformed.  The client should not
 *      retry the request without modification from the previous
 *      attempt.
 *
 * 401 (Unauthorized): The Binding Request did not contain a MESSAGE-
 *      INTEGRITY attribute.
 *
 * 420 (Unknown Attribute): The server did not understand a mandatory
 *      attribute in the request.
 *
 * 430 (Stale Credentials): The Binding Request did contain a MESSAGE-
 *      INTEGRITY attribute, but it used a shared secret that has
 *      expired.  The client should obtain a new shared secret and try
 *      again.
 *
 * 431 (Integrity Check Failure): The Binding Request contained a
 *      MESSAGE-INTEGRITY attribute, but the HMAC failed verification.
 *      This could be a sign of a potential attack, or client
 *      implementation error.
 *
 * 432 (Missing Username): The Binding Request contained a MESSAGE-
 *      INTEGRITY attribute, but not a USERNAME attribute.  Both must be
 *      present for integrity checks.
 *
 * 433 (Use TLS): The Shared Secret request has to be sent over TLS, but
 *      was not received over TLS.
 *
 * 500 (Server Error): The server has suffered a temporary error. The
 *      client should try again.
 *
 * 600 (Global Failure:) The server is refusing to fulfill the request.
 *      The client should not retry.
 *
 * <p>Copyright: Copyright (c) 2003</p>
 * <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
 */
public class ErrorCodeAttribute extends Attribute
{
    // Common error codes
    public static final char BAD_REQUEST   = 400;
    public static final char UNAUTHORIZED  = 401;
    public static final char UNKNOWN_ATTRIBUTE = 420;
    public static final char STALE_CREDENTIALS = 430;
    public static final char INTEGRITY_CHECK_FAILURE = 431;
    public static final char MISSING_USERNAME = 432;
    public static final char USE_TLS = 433;
    public static final char SERVER_ERROR = 500;
    public static final char GLOBAL_FAILURE = 600;


    /**
     * The class represents the hundreds digit of the response code.  The
     * value MUST be between 1 and 6.
     */
    private byte errorClass = 0;

    /**
     * The number represents the response
     * code modulo 100, and its value MUST be between 0 and 99.
     */
    private byte errorNumber = 0;

    /**
     * The reason phrase is meant for user consumption, and can
     * be anything appropriate for the response code.  The lengths of the
     * reason phrases MUST be a multiple of 4 (measured in bytes).
     */
    private String reasonPhrase = null;

    /**
     * Constructs a new ERROR-CODE attribute
     */
    ErrorCodeAttribute()
    {
        super(ERROR_CODE);
    }

    /**
     * A convenience method that sets error class and number according to the
     * specified errorCode.The class represents the hundreds digit of the error code.
     * The value MUST be between 1 and 6.  The number represents the response
     * code modulo 100, and its value MUST be between 0 and 99.
     *
     * @param errorCode the errorCode that this class encapsulates.
     * @throws StunException if errorCode is not a valid error code.
     */
    public void setErrorCode(char errorCode)
        throws StunException
    {
        setErrorClass((byte)(errorCode/100));
        setErrorNumber((byte)(errorCode % 100));
    }

    /**
     * A convenience method that constructs an error code from this Attribute's
     * class and number.
     * @return the code of the error this attribute represents.
     */
    public char getErrorCode()
    {
        return (char)(getErrorClass()*100 + getErrorNumber());
    }


    /**
     * Sets this attribute's error number.
     * @param errorNumber the error number to assign this attribute.
     * @throws StunException if errorNumber is not a valid error number.
     */
    public void setErrorNumber(byte errorNumber)
        throws StunException
    {
        if(errorNumber < 0 || errorNumber > 99)
            throw new StunException(StunException.ILLEGAL_ARGUMENT,
                                    errorNumber + " is not a valid error number!");
        this.errorNumber = errorNumber;
    }

    /**
     * Returns this attribute's error number.
     * @return  this attribute's error number.
     */
    public byte getErrorNumber()
    {
        return this.errorNumber;
    }

    /**
     * Sets this error's error class.
     * @param errorClass this error's error class.
     * @throws StunException if errorClass is not a valid error class.
     */
    public void setErrorClass(byte errorClass)
        throws StunException
    {
        if(errorClass < 0 || errorClass > 99)
            throw new StunException(StunException.ILLEGAL_ARGUMENT,
                                    errorClass + " is not a valid error number!");
        this.errorClass = errorClass;
    }

    /**
     * Returns this error's error class.
     * @return this error's error class.
     */
    public byte getErrorClass()
    {
        return errorClass;
    }


    /**
     * Returns a default reason phrase corresponding to the specified error
     * code, as described by rfc 3489.
     * @param errorCode the code of the error that the reason phrase must
     *                  describe.
     * @return a default reason phrase corresponding to the specified error
     * code, as described by rfc 3489.
     */
    public static String getDefaultReasonPhrase(char errorCode)
    {
        switch(errorCode)
        {
            case 400: return  "(Bad Request): The request was malformed.  The client should not "
                             +"retry the request without modification from the previous attempt.";
            case 401: return  "(Unauthorized): The Binding Request did not contain a MESSAGE-"
                             +"INTEGRITY attribute.";
            case 420: return  "(Unknown Attribute): The server did not understand a mandatory "
                             +"attribute in the request.";
            case 430: return  "(Stale Credentials): The Binding Request did contain a MESSAGE-"
                             +"INTEGRITY attribute, but it used a shared secret that has "
                             +"expired.  The client should obtain a new shared secret and try"
                             +"again";
            case 431: return  "(Integrity Check Failure): The Binding Request contained a "
                             +"MESSAGE-INTEGRITY attribute, but the HMAC failed verification. "
                             +"This could be a sign of a potential attack, or client "
                             +"implementation error.";
            case 432: return  "(Missing Username): The Binding Request contained a MESSAGE-"
                             +"INTEGRITY attribute, but not a USERNAME attribute.  Both must be"
                             +"present for integrity checks.";
            case 433: return  "(Use TLS): The Shared Secret request has to be sent over TLS, but"
                             +"was not received over TLS.";
            case 500: return  "(Server Error): The server has suffered a temporary error. The"
                             +"client should try again.";
            case 600: return "(Global Failure:) The server is refusing to fulfill the request."
                             +"The client should not retry.";

            default:  return "Unknown Error";
        }
    }

    /**
     * Set's a reason phrase. The reason phrase is meant for user consumption,
     * and can be anything appropriate for the response code.  The lengths of
     * the reason phrases MUST be a multiple of 4 (measured in bytes).
     *
     * @param reasonPhrase a reason phrase that describes this error.
     */
    public void setReasonPhrase(String reasonPhrase)
    {
        this.reasonPhrase = reasonPhrase;
    }

    /**
     * Returns the reason phrase. The reason phrase is meant for user consumption,
     * and can be anything appropriate for the response code.  The lengths of
     * the reason phrases MUST be a multiple of 4 (measured in bytes).
     *
     * @return reasonPhrase a reason phrase that describes this error.
     */
    public String getReasonPhrase()
    {
        return this.reasonPhrase;
    }

    /**
     * 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;
    }

    public static final String NAME = "ERROR-CODE";

    /**
     * Returns the length of this attribute's body.
     * @return the length of this attribute's value.
     */
    public char getDataLength()
    {
        char len = (char)( 4 //error code numbers
                           + (char)(
                                    reasonPhrase == null? 0
                                                          :reasonPhrase.length()*2
                                    ));

        /*
         * According to rfc 3489 The length of the
         * reason phrases MUST be a multiple of 4 (measured in bytes)
         */
        len += 4 - (len%4);
        return len;
    }

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

        //Type
        binValue[0] = (byte) (getAttributeType() >> 8);
        binValue[1] = (byte) (getAttributeType() & 0x00FF);
        //Length
        binValue[2] = (byte) (getDataLength() >> 8);
        binValue[3] = (byte) (getDataLength() & 0x00FF);

        //Not used
        binValue[4] = 0x00;
        binValue[5] = 0x00;

        //Error code
        binValue[6] = getErrorClass();
        binValue[7] = getErrorNumber();

        int offset = 8;
        char chars[] = reasonPhrase.toCharArray();
        for (int i = 0; i < reasonPhrase.length(); i++, offset += 2) {
            binValue[offset]   = (byte)(chars[i]>>8);
            binValue[offset+1] = (byte)(chars[i] & 0xFF);
        }

        //The lengths of the reason phrases MUST be a multiple of 4 (measured
        //in bytes)
        if( reasonPhrase.length()%4 != 0)
        {
            binValue[binValue.length - 2] = (byte) ( ( (int) ' ') >> 8);
            binValue[binValue.length - 1] = (byte) ( ( (int) ' ') & 0x00FF);
        }

        return binValue;
    }

    /**
     * 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 ErrorCodeAttribute)
             || obj == null)
             return false;

         if (obj == this)
             return true;

         ErrorCodeAttribute att = (ErrorCodeAttribute) obj;
         if (att.getAttributeType() != getAttributeType()
             || att.getDataLength() != getDataLength()
             //compare data
             || att.getErrorClass() != getErrorClass()
             || att.getErrorNumber()!= getErrorNumber()
             || ( att.getReasonPhrase() != null
                  && !att.getReasonPhrase().equals(getReasonPhrase()))
             )
             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
    {

        offset += 2; //skip the 0s

        //Error code
        setErrorClass(attributeValue[offset++]);
        setErrorNumber(attributeValue[offset++]);

        //Reason Phrase
        char reasonPhrase[] = new char[(length-4)/2];

        for (int i = 0; i < reasonPhrase.length; i++, offset+=2) {
            reasonPhrase[i] =
                (char)(attributeValue[offset] | attributeValue[offset+1]);
        }
        setReasonPhrase(new String(reasonPhrase).trim());

    }


}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -