ONOS-2739 - OSPF Basic Packet Structures , which includes encoding and decoding

Change-Id: I33b48593ec38d28bdff215ce3a608a6d085a9077
diff --git a/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/ospfpacket/types/HelloPacket.java b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/ospfpacket/types/HelloPacket.java
new file mode 100644
index 0000000..cf0d6aa
--- /dev/null
+++ b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/ospfpacket/types/HelloPacket.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * 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.onosproject.ospf.protocol.ospfpacket.types;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.primitives.Bytes;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.ospf.exceptions.OspfErrorType;
+import org.onosproject.ospf.exceptions.OspfParseException;
+import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader;
+import org.onosproject.ospf.protocol.util.OspfPacketType;
+import org.onosproject.ospf.protocol.util.OspfUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Defines an OSPF Hello Message, and the fields and methods to access it.
+ * Hello packets are OSPF packet type 1. These packets are sent
+ * periodically on all interfaces in order to establish and
+ * maintain neighbor relationships.
+ */
+public class HelloPacket extends OspfPacketHeader {
+
+    /*
+              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
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |   Version #   |       1       |         Packet length         |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                          Router ID                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                           Area ID                             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |           Checksum            |             AuType            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                       Authentication                          |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                       Authentication                          |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                        Network Mask                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |         HelloInterval         |    Options    |    Rtr Pri    |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                     RouterDeadInterval                        |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                      Designated Router                        |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                   Backup Designated Router                    |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                          Neighbor                             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |                              ...                              |
+
+            Hello Message Format
+            REFERENCE : RFC 2328
+    */
+
+    private static final Logger log = LoggerFactory.getLogger(HelloPacket.class);
+    private Ip4Address networkMask;
+    private int options;
+    private int helloInterval;
+    private int routerPriority;
+    private int routerDeadInterval;
+    private Ip4Address bdr;
+    private Ip4Address dr;
+    private List<Ip4Address> neighborAddress = new ArrayList<>();
+
+    /**
+     * Creates an instance of Hello packet.
+     */
+    public HelloPacket() {
+    }
+
+    /**
+     * Creates an instance of Hello packet.
+     *
+     * @param ospfHeader OSPF header instance.
+     */
+    public HelloPacket(OspfPacketHeader ospfHeader) {
+        populateHeader(ospfHeader);
+    }
+
+    /**
+     * Gets network mask.
+     *
+     * @return network mask
+     */
+    public Ip4Address networkMask() {
+        return networkMask;
+    }
+
+    /**
+     * Sets network mask.
+     *
+     * @param networkMask network mask
+     */
+    public void setNetworkMask(Ip4Address networkMask) {
+        this.networkMask = networkMask;
+    }
+
+    /**
+     * Gets BDRs IP address.
+     *
+     * @return BDRs IP address
+     */
+    public Ip4Address bdr() {
+        return bdr;
+    }
+
+    /**
+     * Sets BDR IP address.
+     *
+     * @param bdr BDR IP address
+     */
+    public void setBdr(Ip4Address bdr) {
+        this.bdr = bdr;
+    }
+
+    /**
+     * Gets DRs IP address.
+     *
+     * @return DRs IP address
+     */
+    public Ip4Address dr() {
+        return dr;
+    }
+
+    /**
+     * Sets DRs IP address.
+     *
+     * @param dr DRs IP address
+     */
+    public void setDr(Ip4Address dr) {
+        this.dr = dr;
+    }
+
+    /**
+     * Adds neighbor to map.
+     *
+     * @param neighborID neighbors id
+     */
+    public void addNeighbor(Ip4Address neighborID) {
+        if (!neighborAddress.contains(neighborID)) {
+            neighborAddress.add(neighborID);
+        }
+    }
+
+    /**
+     * Checks neighbor is in map or not.
+     *
+     * @param neighborID neighbors id
+     * @return true if neighbor exist else false
+     */
+    public boolean containsNeighbour(Ip4Address neighborID) {
+        return (neighborAddress.contains(neighborID)) ? true : false;
+    }
+
+    /**
+     * Gets options value.
+     *
+     * @return options value
+     */
+    public int options() {
+        return options;
+    }
+
+    /**
+     * Sets options value.
+     *
+     * @param options options value
+     */
+    public void setOptions(int options) {
+        this.options = options;
+    }
+
+    /**
+     * Gets router priority.
+     *
+     * @return routerPriority
+     */
+    public int routerPriority() {
+        return routerPriority;
+    }
+
+    /**
+     * Sets router priority.
+     *
+     * @param routerPriority router priority
+     */
+    public void setRouterPriority(int routerPriority) {
+        this.routerPriority = routerPriority;
+    }
+
+    /**
+     * Gets hello interval.
+     *
+     * @return hello Interval
+     */
+    public int helloInterval() {
+        return helloInterval;
+    }
+
+    /**
+     * Sets hello Interval.
+     *
+     * @param helloInterval hello Interval
+     */
+    public void setHelloInterval(int helloInterval) {
+        this.helloInterval = helloInterval;
+    }
+
+    /**
+     * Gets router dead interval.
+     *
+     * @return router dead interval
+     */
+    public int routerDeadInterval() {
+        return routerDeadInterval;
+    }
+
+    /**
+     * Sets router dead interval.
+     *
+     * @param routerDeadInterval router dead interval
+     */
+    public void setRouterDeadInterval(int routerDeadInterval) {
+        this.routerDeadInterval = routerDeadInterval;
+    }
+
+    @Override
+    public OspfPacketType ospfMessageType() {
+        return OspfPacketType.HELLO;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer channelBuffer) throws OspfParseException {
+
+        try {
+            byte[] tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+            channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+            this.setNetworkMask(Ip4Address.valueOf(tempByteArray));
+            this.setHelloInterval(channelBuffer.readShort());
+            this.setOptions(channelBuffer.readByte());
+            this.setRouterPriority(channelBuffer.readByte() & 0xff);
+            this.setRouterDeadInterval(channelBuffer.readInt());
+            tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+            channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+            this.setDr(Ip4Address.valueOf(tempByteArray));
+            tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+            channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+            this.setBdr(Ip4Address.valueOf(tempByteArray));
+
+            while (channelBuffer.readableBytes() > 0) {
+                tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+                channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+                this.addNeighbor(Ip4Address.valueOf(tempByteArray));
+            }
+
+        } catch (Exception e) {
+            log.debug("Error::HelloPacket:: {}", e.getMessage());
+            throw new OspfParseException(OspfErrorType.MESSAGE_HEADER_ERROR, OspfErrorType.BAD_MESSAGE_LENGTH);
+        }
+    }
+
+    @Override
+    public byte[] asBytes() {
+
+        byte[] helloMessage = null;
+        byte[] helloHeader = getHelloHeaderAsByteArray();
+        byte[] helloBody = getHelloBodyAsByteArray();
+        helloMessage = Bytes.concat(helloHeader, helloBody);
+
+        log.debug("HelloPacket::asBytes::Hello asBytes:: {}", helloMessage);
+
+        return helloMessage;
+    }
+
+    /**
+     * Gets hello header as byte array.
+     *
+     * @return hello header
+     */
+    public byte[] getHelloHeaderAsByteArray() {
+        List<Byte> headerLst = new ArrayList<>();
+        try {
+            headerLst.add((byte) this.ospfVersion());
+            headerLst.add((byte) this.ospfType());
+            headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.ospfPacLength())));
+            headerLst.addAll(Bytes.asList(this.routerId().toOctets()));
+            headerLst.addAll(Bytes.asList(this.areaId().toOctets()));
+            headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.checksum())));
+            headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.authType())));
+            //Authentication is 0 always. Total 8 bytes consist of zero
+            byte[] auth = new byte[OspfUtil.EIGHT_BYTES];
+            headerLst.addAll(Bytes.asList(auth));
+        } catch (Exception e) {
+            log.debug("Error::getHelloHeaderAsByteArray {}", e.getMessage());
+            return Bytes.toArray(headerLst);
+        }
+
+        return Bytes.toArray(headerLst);
+    }
+
+    /**
+     * Gets hello body as byte array.
+     *
+     * @return hello body as byte array
+     */
+    public byte[] getHelloBodyAsByteArray() {
+        List<Byte> bodyLst = new ArrayList<>();
+
+        try {
+            bodyLst.addAll(Bytes.asList(this.networkMask().toOctets()));
+            bodyLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.helloInterval())));
+            bodyLst.add((byte) this.options());
+            bodyLst.add((byte) this.routerPriority());
+            bodyLst.addAll(Bytes.asList(OspfUtil.convertToFourBytes(this.routerDeadInterval())));
+            bodyLst.addAll(Bytes.asList(this.dr().toOctets()));
+            bodyLst.addAll(Bytes.asList(this.bdr().toOctets()));
+            for (Ip4Address neighbour : neighborAddress) {
+                bodyLst.addAll(Bytes.asList(neighbour.toOctets()));
+            }
+
+        } catch (Exception e) {
+            log.debug("Error::getHelloBodyAsByteArray {}", e.getMessage());
+            return Bytes.toArray(bodyLst);
+        }
+
+        return Bytes.toArray(bodyLst);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("networkMask", networkMask)
+                .add("options", options)
+                .add("helloInterval", helloInterval)
+                .add("routerPriority", routerPriority)
+                .add("routerDeadInterval", routerDeadInterval)
+                .add("bdr", bdr)
+                .add("dr", dr)
+                .toString();
+    }
+}
\ No newline at end of file