Completed COPS Message refactoring. Was planning on one additional patch starting...
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / stack / COPSHeader.java
index 90a0a630b2b0844360d737f59990abf0085d569b..27821e2aa03b57e696377057a65fbc7b19adbd9b 100644 (file)
-/*\r
- * Copyright (c) 2003 University of Murcia.  All rights reserved.\r
- * --------------------------------------------------------------\r
- * For more information, please see <http://www.umu.euro6ix.org/>.\r
- */\r
-\r
-package org.umu.cops.stack;\r
-\r
-import java.io.IOException;\r
-import java.io.OutputStream;\r
-import java.net.Socket;\r
-\r
-/**\r
- * COPS Header (RFC 2748 pag. 6)\r
- *\r
- *   Each COPS message consists of the COPS header followed by a number of\r
- *   typed objects.\r
- *\r
- *             0              1              2              3\r
- *     +--------------+--------------+--------------+--------------+\r
- *     |Version| Flags|    Op Code   |       Client-type           |\r
- *     +--------------+--------------+--------------+--------------+\r
- *     |                      Message Length                       |\r
- *     +--------------+--------------+--------------+--------------+\r
- *\r
- *     Global note: //// implies field is reserved, set to 0.\r
- *\r
- *       The fields in the header are:\r
- *         Version: 4 bits\r
- *             COPS version number. Current version is 1.\r
- *\r
- *         Flags: 4 bits\r
- *             Defined flag values (all other flags MUST be set to 0):\r
- *               0x1 Solicited Message Flag Bit\r
- *                This flag is set when the message is solicited by\r
- *                another COPS message. This flag is NOT to be set\r
- *                (value=0) unless otherwise specified.\r
- *\r
- *         Op Code: 8 bits\r
- *            The COPS operations:\r
- *              1 = Request                 (REQ)\r
- *              2 = Decision                (DEC)\r
- *              3 = Report State            (RPT)\r
- *              4 = Delete Request State    (DRQ)\r
- *              5 = Synchronize State Req   (SSQ)\r
- *              6 = Client-Open             (OPN)\r
- *              7 = Client-Accept           (CAT)\r
- *              8 = Client-Close            (CC)\r
- *              9 = Keep-Alive              (KA)\r
- *              10= Synchronize Complete    (SSC)\r
- *\r
- *       Client-type: 16 bits\r
- *\r
- *\r
- * @version COPSHeader.java, v 1.00 2003\r
- *\r
- */\r
-public class COPSHeader {\r
-\r
-    public final static byte COPS_OP_REQ = 1;\r
-    public final static byte COPS_OP_DEC = 2;\r
-    public final static byte COPS_OP_RPT = 3;\r
-    public final static byte COPS_OP_DRQ = 4;\r
-    public final static byte COPS_OP_SSQ = 5;\r
-    public final static byte COPS_OP_OPN = 6;\r
-    public final static byte COPS_OP_CAT = 7;\r
-    public final static byte COPS_OP_CC = 8;\r
-    public final static byte COPS_OP_KA = 9;\r
-    public final static byte COPS_OP_SSC = 10;\r
-\r
-    public final static byte COPS_FLAG_NULL = 0;\r
-    public final static byte COPS_FLAG_SOLICITED = 1;\r
-\r
-    private byte _versionNflg;\r
-    private byte _opCode;\r
-    private short _cType;\r
-    private int _msgLength;\r
-\r
-    public COPSHeader() {\r
-        _versionNflg = 0x10;\r
-        _opCode = 0;\r
-        _cType = 0;\r
-        _msgLength = 0;\r
-    }\r
-\r
-    public COPSHeader(byte opCode, short clientType) {\r
-        _versionNflg = 0x10;\r
-        _opCode = opCode;\r
-        _cType = clientType;\r
-        _msgLength = 0;\r
-        if (isAKeepAlive()) _cType = 0;\r
-    }\r
-\r
-    public COPSHeader(byte opCode) {\r
-        _versionNflg = 0x10;\r
-        _opCode = opCode;\r
-        _cType = 0;\r
-        _msgLength = 0;\r
-        if (isAKeepAlive()) _cType = 0;\r
-    }\r
-\r
-    /**\r
-          Parse data and create COPSHeader object\r
-     */\r
-    public COPSHeader(byte[] buf) {\r
-        _versionNflg = (byte) buf[0];\r
-        _opCode = (byte) buf[1];\r
-        _cType |= ((short) buf[2]) << 8;\r
-        _cType |= ((short) buf[3]) & 0xFF;\r
-        _msgLength |= ((short) buf[4]) << 24;\r
-        _msgLength |= ((short) buf[5]) << 16;\r
-        _msgLength |= ((short) buf[6]) << 8;\r
-        _msgLength |= ((short) buf[7]) & 0xFF;\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message Request, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isARequest() {\r
-        return (_opCode == COPS_OP_REQ);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message Decision, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isADecision() {\r
-        return (_opCode == COPS_OP_DEC);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message Report, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isAReport() {\r
-        return (_opCode == COPS_OP_RPT);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message DeleteRequest, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isADeleteReq() {\r
-        return (_opCode == COPS_OP_DRQ);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message SyncStateReq, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isASyncStateReq() {\r
-        return (_opCode == COPS_OP_SSQ);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message ClientOpen, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isAClientOpen() {\r
-        return (_opCode == COPS_OP_OPN);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message ClientAccept, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isAClientAccept() {\r
-        return (_opCode == COPS_OP_CAT);\r
-    }\r
-\r
-    /**\r
-     * If operation code corresponds with a message ClientClose, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isAClientClose() {\r
-        return (_opCode == COPS_OP_CC);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message KeepAlive, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isAKeepAlive() {\r
-        return (_opCode == COPS_OP_KA);\r
-    }\r
-\r
-    /**\r
-     * If the operation code corresponds with a message SSC, return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isASyncComplete() {\r
-        return (_opCode == COPS_OP_SSC);\r
-    }\r
-\r
-    /**\r
-     * Get message length\r
-     *\r
-     * @return   an int\r
-     *\r
-     */\r
-    public int getMsgLength() {\r
-        return _msgLength;\r
-    }\r
-\r
-    /**\r
-     * Get header length\r
-     *\r
-     * @return   an int\r
-     *\r
-     */\r
-    public int getHdrLength() {\r
-        // return (sizeof(u_int32_t) * 2);\r
-        return ( 8 );\r
-    }\r
-\r
-    /**\r
-     * Get Operation Code\r
-     *\r
-     * @return   a byte\r
-     *\r
-     */\r
-    public byte getOpCode() {\r
-        return _opCode;\r
-    }\r
-\r
-    /**\r
-     * Set the solicitation flag\r
-     *\r
-     * @param    flg                 a  byte\r
-     *\r
-     */\r
-    public void setFlag(byte flg) {\r
-        _versionNflg &= 0x10;\r
-        _versionNflg |= flg;\r
-    }\r
-\r
-    /**\r
-     * Returns the flags field\r
-     * @return aByte     Flags field in header\r
-     */\r
-    public byte getFlags() { //OJO\r
-        return (byte) (_versionNflg & 0x0f);\r
-    }\r
-\r
-    /**\r
-     * Set the client-type\r
-     *\r
-     * @param    cType               a  short\r
-     *\r
-     */\r
-    public void setClientType(short cType) {\r
-        _cType = cType;\r
-    };\r
-\r
-    /**\r
-     * Set the message length\r
-     *\r
-     * @param    len                 an int\r
-     *\r
-     * @throws   COPSException\r
-     *\r
-     */\r
-    public void setMsgLength(int len) throws COPSException {\r
-        if ((len % 4) != 0)\r
-            throw new COPSException ("Message is not aligned on 32 bit intervals");\r
-        _msgLength = len + 8;\r
-    }\r
-\r
-    /**\r
-     * Get client-type\r
-     *\r
-     * @return   a short\r
-     *\r
-     */\r
-    public short getClientType() {\r
-        return (_cType);\r
-    };\r
-\r
-    /**\r
-     * Always return true\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isCOPSHeader() {\r
-        return true;\r
-    };\r
-\r
-    /**\r
-     * Writes object to given network socket in network byte order\r
-     *\r
-     * @param    id                  a  Socket\r
-     *\r
-     * @throws   IOException\r
-     *\r
-     */\r
-    public void writeData(Socket id) throws IOException {\r
-        byte buf[] = new byte[8];\r
-\r
-        buf[0] = (byte) _versionNflg;\r
-        buf[1] = (byte) _opCode;\r
-        buf[2] = (byte) (_cType >> 8);\r
-        buf[3] = (byte) _cType;\r
-        buf[4] = (byte) (_msgLength >> 24);\r
-        buf[5] = (byte) (_msgLength >> 16);\r
-        buf[6] = (byte) (_msgLength >> 8);\r
-        buf[7] = (byte) _msgLength;\r
-\r
-        COPSUtil.writeData(id, buf, 8);\r
-    }\r
-\r
-    /**\r
-     * Get an object textual description\r
-     *\r
-     * @return   a String\r
-     *\r
-     */\r
-    public String toString() {\r
-        String str = new String();\r
-\r
-        str += "**MSG HEADER** \n";\r
-        str += "Version: " + (_versionNflg >> 4) + "\n";\r
-        str += "Flags: " + (_versionNflg & 0x01) + "\n";\r
-        str += "OpCode: " + _opCode + "\n";\r
-        str += "Client-type: " + _cType + "\n";\r
-        str += "Message-length(bytes): " + _msgLength + "\n";\r
-        return str;\r
-    }\r
-\r
-    /**\r
-     * Write an object textual description in the output stream\r
-     *\r
-     * @param    os                  an OutputStream\r
-     *\r
-     * @throws   IOException\r
-     *\r
-     */\r
-    public void dump(OutputStream os) throws IOException {\r
-        os.write(new String("**MSG HEADER**" + "\n").getBytes());\r
-        os.write(new String("Version: " + (_versionNflg >> 4) + "\n").getBytes());\r
-        os.write(new String("Flags: " + (_versionNflg & 0x01) + "\n").getBytes());\r
-        os.write(new String("OpCode: " + _opCode + "\n").getBytes());\r
-        os.write(new String("Client-type: " + _cType + "\n").getBytes());\r
-        os.write(new String("Message-length(bytes): " + _msgLength + "\n").getBytes());\r
-    }\r
-}\r
-\r
-\r
-\r
-\r
+/*
+ * Copyright (c) 2003 University of Murcia.  All rights reserved.
+ * --------------------------------------------------------------
+ * For more information, please see <http://www.umu.euro6ix.org/>.
+ */
+
+package org.umu.cops.stack;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * COPS Header (RFC 2748 pag. 6)
+ *
+ *   Each COPS message consists of the COPS header followed by a number of
+ *   typed objects.
+ *
+ *             0              1              2              3
+ *     +--------------+--------------+--------------+--------------+
+ *     |Version| Flags|    Op Code   |       Client-type           |
+ *     +--------------+--------------+--------------+--------------+
+ *     |                      Message Length                       |
+ *     +--------------+--------------+--------------+--------------+
+ *
+ *     Global note: //// implies field is reserved, set to 0.
+ *
+ *       The fields in the header are:
+ *         Version: 4 bits
+ *             COPS version number. Current version is 1.
+ *
+ *         Flags: 4 bits
+ *             Defined flag values (all other flags MUST be set to 0):
+ *               0x1 Solicited Message Flag Bit
+ *                This flag is set when the message is solicited by
+ *                another COPS message. This flag is NOT to be set
+ *                (value=0) unless otherwise specified.
+ *
+ *         Op Code: 8 bits
+ *            The COPS operations:
+ *              1 = Request                 (REQ)
+ *              2 = Decision                (DEC)
+ *              3 = Report State            (RPT)
+ *              4 = Delete Request State    (DRQ)
+ *              5 = Synchronize State Req   (SSQ)
+ *              6 = Client-Open             (OPN)
+ *              7 = Client-Accept           (CAT)
+ *              8 = Client-Close            (CC)
+ *              9 = Keep-Alive              (KA)
+ *              10= Synchronize Complete    (SSC)
+ *
+ *       Client-type: 16 bits
+ *
+ *
+ * @version COPSHeader.java, v 1.00 2003
+ *
+ */
+public class COPSHeader {
+
+    /**
+     * Map allowing for the quick retrieval of the client type based on the numeric value coming in via the
+     * COPS payload.
+     */
+    final static Map<Integer, ClientType> VAL_TO_CT = new ConcurrentHashMap<>();
+    static {
+        VAL_TO_CT.put(ClientType.NA.ordinal(), ClientType.NA);
+        VAL_TO_CT.put(ClientType.TYPE_1.ordinal(), ClientType.TYPE_1);
+        VAL_TO_CT.put(ClientType.TYPE_2.ordinal(), ClientType.TYPE_2);
+        VAL_TO_CT.put(ClientType.TYPE_3.ordinal(), ClientType.TYPE_3);
+    }
+
+    /**
+     * Map allowing for the quick retrieval of the operation based on the numeric value coming in via the
+     * COPS payload.
+     */
+    final static Map<Integer, OPCode> VAL_TO_OP = new ConcurrentHashMap<>();
+    static {
+        VAL_TO_OP.put(OPCode.NA.ordinal(), OPCode.NA);
+        VAL_TO_OP.put(OPCode.REQ.ordinal(), OPCode.REQ);
+        VAL_TO_OP.put(OPCode.DEC.ordinal(), OPCode.DEC);
+        VAL_TO_OP.put(OPCode.RPT.ordinal(), OPCode.RPT);
+        VAL_TO_OP.put(OPCode.DRQ.ordinal(), OPCode.DRQ);
+        VAL_TO_OP.put(OPCode.SSQ.ordinal(), OPCode.SSQ);
+        VAL_TO_OP.put(OPCode.OPN.ordinal(), OPCode.OPN);
+        VAL_TO_OP.put(OPCode.CAT.ordinal(), OPCode.CAT);
+        VAL_TO_OP.put(OPCode.CC.ordinal(), OPCode.CC);
+        VAL_TO_OP.put(OPCode.KA.ordinal(), OPCode.KA);
+        VAL_TO_OP.put(OPCode.SSC.ordinal(), OPCode.SSC);
+    }
+
+    /**
+     * Represents the PCMM version number of the message
+     * Holds the first nibble of the COPS message
+     */
+    private final int _pcmmVersion;
+
+    /**
+     * Represents the second nibble of the message where solicited decisions will be set to 1 else 0
+     * Values 0 = UNSOLICITED | 1 = SOLICITED
+     */
+    private final Flag _flag;
+
+    /**
+     * Represents the type of operation which will be used to determine the type of COPSMsg this header will be a
+     * part of.
+     * Uses the byte value contained in the second byte of the message and inbound messages should use the constant
+     * Map VAL_TO_CT during construction
+     */
+    private final OPCode _opCode;
+
+    /**
+     * Represents client type which there are currently 3 types supported.
+     * Uses the 3rd byte of the message and inbound messages should use the constant Map VAL_TO_OP during construction
+     */
+    private final ClientType _cType;
+
+    /**
+     * Easy constructor that implies version 1 and UNSOLICITED flag.
+     *
+     * User should leverage the main constructor below and set the version and flags.
+     *
+     * @param opCode - the Operation code denoting the type of message
+     * @param clientType - the client type generally denotes if it is an Ipv4 (TYPE_1) else Ipv6
+     * @throws java.lang.IllegalArgumentException
+     */
+    @Deprecated
+    public COPSHeader(final OPCode opCode, final ClientType clientType) {
+        this(1, Flag.UNSOLICITED, opCode, clientType);
+    }
+
+    /**
+     * Should be the main constructor.
+     * @param version - PCMM Version
+     * @param flag - the header flag
+     * @param opCode - the COPS operation code
+     * @param clientType - the type of client interfacing
+     * @throws java.lang.IllegalArgumentException
+     */
+    public COPSHeader(final int version, final Flag flag, final OPCode opCode, final ClientType clientType) {
+        if(version < 1) throw new IllegalArgumentException("Invalid version number - " + version);
+        if(flag == null) throw new IllegalArgumentException("Flag is null");
+        if(opCode == null) throw new IllegalArgumentException("OPCode is null");
+        if(clientType == null) throw new IllegalArgumentException("clientType is null");
+        _pcmmVersion = version;
+        _flag = flag;
+        _opCode = opCode;
+        _cType = clientType;
+
+        // TODO - Determine why this??? - remove until this makes some sense
+//        if (opCode.equals(OPCode.KA)) _cType = ClientType.NA;
+//        else _cType = clientType;
+    }
+
+    // Getters
+    public int getPcmmVersion() { return _pcmmVersion; }
+    public Flag getFlag() { return _flag; }
+
+    /**
+     * Get header length
+     * @return   an int
+     */
+    public int getHdrLength() {
+        return 8;
+    }
+
+    /**
+     * Get Operation Code
+     * @return   a byte
+     */
+    public OPCode getOpCode() {
+        return _opCode;
+    }
+
+    /**
+     * Get client-type
+     * @return   a short
+     */
+    public ClientType getClientType() {
+        return _cType;
+    }
+
+    /**
+     * Writes object to given network socket in network byte order
+     * @param    socket                  a  Socket
+     * @throws   IOException
+     */
+    public void writeData(final Socket socket, final int msgLength) throws IOException {
+        byte buf[] = new byte[8];
+        buf[0] = (byte) COPSMsgParser.combineNibbles((byte)_pcmmVersion, (byte) _flag.ordinal());
+        buf[1] = (byte) _opCode.ordinal();
+        buf[2] = (byte) (_cType.ordinal() >> 8);
+        buf[3] = (byte) _cType.ordinal();
+        buf[4] = (byte) (msgLength >> 24);
+        buf[5] = (byte) (msgLength >> 16);
+        buf[6] = (byte) (msgLength >> 8);
+        buf[7] = (byte) msgLength;
+        COPSUtil.writeData(socket, buf, 8);
+    }
+
+    @Override
+    public String toString() {
+        return "**MSG HEADER** \n"
+                + "Version: " + _pcmmVersion + "\n"
+                + "Flags: " + _flag + "\n"
+                + "OpCode: " + _opCode + "\n"
+                + "Client-type: " + _cType + "\n";
+    }
+
+    /**
+     * Write an object textual description in the output stream
+     * @param    os                  an OutputStream
+     * @throws   IOException
+     */
+    public void dump(OutputStream os) throws IOException {
+        os.write(("**MSG HEADER**" + "\n").getBytes());
+        os.write(("Version: " + _pcmmVersion + "\n").getBytes());
+        os.write(("Flags: " + _flag + "\n").getBytes());
+        os.write(("OpCode: " + _opCode + "\n").getBytes());
+        os.write(("Client-type: " + _cType + "\n").getBytes());
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof COPSHeader)) {
+            return false;
+        }
+
+        final COPSHeader header = (COPSHeader) o;
+
+        return _pcmmVersion == header._pcmmVersion && _cType == header._cType && _flag == header._flag &&
+                _opCode == header._opCode;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = _pcmmVersion;
+        result = 31 * result + _flag.hashCode();
+        result = 31 * result + _opCode.hashCode();
+        result = 31 * result + _cType.hashCode();
+        return result;
+    }
+
+    /**
+     * The types of COPS clients
+     *
+     * 0 = N/A - placeholder for the invalid value of 0
+     * 1 = TYPE_1 - Represents legacy endpoints (PC applications, game consoles) lacking QoS awareness or
+     *              signaling capabilities.
+     * 2 = TYPE_2 - Represents a client that is similar to PacketCable 1.x telophony MTA which should support Qos
+     *              signaling.
+     * 3 = TYPE_3 - Represents QoS treatment from the access network withouth Application Manager interaction
+     */
+    public enum ClientType {
+        NA, TYPE_1, TYPE_2, TYPE_3
+    }
+
+    /**
+     * Represents the COPS Operation code and byte value corresponds to the item's ordinal value
+     *            The COPS operations:
+     *              0 = N/A - placeholder for the invalid value of 0
+     *              1 = Request                 (REQ)
+     *              2 = Decision                (DEC)
+     *              3 = Report State            (RPT)
+     *              4 = Delete Request State    (DRQ)
+     *              5 = Synchronize State Req   (SSQ)
+     *              6 = Client-Open             (OPN)
+     *              7 = Client-Accept           (CAT)
+     *              8 = Client-Close            (CC)
+     *              9 = Keep-Alive              (KA)
+     *              10= Synchronize Complete    (SSC)
+     */
+    public enum OPCode {
+        NA, REQ, DEC, RPT, DRQ, SSQ, OPN, CAT, CC, KA, SSC
+    }
+
+    /**
+     * Represents the COPS flags value where the inbound nibble value maps to the ordinal values.
+     */
+    public enum Flag {
+        UNSOLICITED, SOLICITED
+    }
+
+}
+
+
+
+