org.opendaylight.netvirt.dhcpservice.api.DHCP.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.netvirt.dhcpservice.api.DHCP.java

Source

/*
 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.opendaylight.netvirt.dhcpservice.api;

import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.BOOTREPLY;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_MAX_SIZE;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_MIN_SIZE;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.DHCP_NOOPT_HDR_SIZE;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.HTYPE_ETHER;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.MAGIC_COOKIE;
import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.OPT_MESSAGE_TYPE;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.controller.liblldp.BitBufferHelper;
import org.opendaylight.controller.liblldp.BufferException;
import org.opendaylight.controller.liblldp.HexEncode;
import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.controller.liblldp.Packet;
import org.opendaylight.controller.liblldp.PacketException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DHCP extends Packet {
    protected static final Logger LOG = LoggerFactory.getLogger(DHCP.class);
    private static final String OP = "Op";
    private static final String HTYPE = "Htype";
    private static final String HLEN = "Hlen";
    private static final String HOPS = "Hops";
    private static final String XID = "Xid";
    private static final String SECS = "Secs";
    private static final String FLAGS = "Flags";
    private static final String CIADDR = "Ciaddr";
    private static final String YIADDR = "Yiaddr";
    private static final String SIADDR = "Siaddr";
    private static final String GIADDR = "Giaddr";
    private static final String CHADDR = "Chaddr";
    private static final String SNAME = "Sname";
    private static final String FILE = "File";
    private static final String MCOOKIE = "Mcookie";
    private static final String OPTIONS = "Options";
    private DHCPOptions dhcpOptions = null;

    private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
        private static final long serialVersionUID = 1L;
        {
            put(OP, new ImmutablePair<>(0, 8));
            put(HTYPE, new ImmutablePair<>(8, 8));
            put(HLEN, new ImmutablePair<>(16, 8));
            put(HOPS, new ImmutablePair<>(24, 8));
            put(XID, new ImmutablePair<>(32, 32));
            put(SECS, new ImmutablePair<>(64, 16));
            put(FLAGS, new ImmutablePair<>(80, 16));
            put(CIADDR, new ImmutablePair<>(96, 32));
            put(YIADDR, new ImmutablePair<>(128, 32));
            put(SIADDR, new ImmutablePair<>(160, 32));
            put(GIADDR, new ImmutablePair<>(192, 32));
            put(CHADDR, new ImmutablePair<>(224, 128));
            put(SNAME, new ImmutablePair<>(352, 512));
            put(FILE, new ImmutablePair<>(864, 1024));
            put(MCOOKIE, new ImmutablePair<>(1888, 32));
            put(OPTIONS, new ImmutablePair<>(1920, 0));
        }
    };

    private final Map<String, byte[]> fieldValues;

    public DHCP() {
        this(false);
    }

    public DHCP(boolean writeAccess) {
        super(writeAccess);
        fieldValues = new HashMap<>();
        hdrFieldCoordMap = fieldCoordinates;
        hdrFieldsMap = fieldValues;
        corrupted = false;

        setOp(BOOTREPLY);
        setHtype(HTYPE_ETHER);
        setHlen((byte) 6);
        setHops((byte) 0);
        setXid(0);
        setSecs((short) 0);
        setFlags((short) 0);
        setCiaddr(0);
        setYiaddr(0);
        setSiaddr(0);
        setGiaddr(0);
        setChaddr(new byte[16]);
        setSname(new byte[64]);
        setFile(new byte[128]);
        setMcookie(MAGIC_COOKIE);
        setOptions(new byte[0]);
        this.dhcpOptions = new DHCPOptions();
    }

    //Getters
    public byte getOp() {
        return (BitBufferHelper.getByte(fieldValues.get(OP)));
    }

    public byte getHtype() {
        return (BitBufferHelper.getByte(fieldValues.get(HTYPE)));
    }

    public byte getHlen() {
        return (BitBufferHelper.getByte(fieldValues.get(HLEN)));
    }

    public byte getHops() {
        return (BitBufferHelper.getByte(fieldValues.get(HOPS)));
    }

    public int getXid() {
        return (BitBufferHelper.getInt(fieldValues.get(XID)));
    }

    public short getSecs() {
        return (BitBufferHelper.getShort(fieldValues.get(SECS)));
    }

    public short getFlags() {
        return (BitBufferHelper.getShort(fieldValues.get(FLAGS)));
    }

    public byte[] getCiaddr() {
        return fieldValues.get(CIADDR);
    }

    public byte[] getYiaddr() {
        return fieldValues.get(YIADDR);
    }

    public byte[] getSiaddr() {
        return fieldValues.get(SIADDR);
    }

    public InetAddress getSiaddrAsInetAddr() {
        return DHCPUtils.byteArrayToInetAddr(fieldValues.get(SIADDR));
    }

    public byte[] getGiaddr() {
        return fieldValues.get(GIADDR);
    }

    public byte[] getChaddr() {
        return fieldValues.get(CHADDR);
    }

    public byte[] getSname() {
        return fieldValues.get(SNAME);
    }

    public byte[] getFile() {
        return fieldValues.get(FILE);
    }

    public int getMCookie() {
        return (BitBufferHelper.getInt(fieldValues.get(MCOOKIE)));
    }

    public byte[] getOptions() {
        return fieldValues.get(OPTIONS);
    }

    //    TODO:
    //    public byte[] getPadding() {
    //        return this.pad;
    //    }

    // Setters
    @Override
    public void setHeaderField(String headerField, byte[] readValue) {
        if (headerField.equals(OPTIONS) && (readValue == null || readValue.length == 0)) {
            hdrFieldsMap.remove(headerField);
            return;
        }
        hdrFieldsMap.put(headerField, readValue);
    }

    public DHCP setOp(byte dhcpOp) {
        byte[] op = BitBufferHelper.toByteArray(dhcpOp);
        fieldValues.put(OP, op);
        return this;
    }

    public DHCP setHtype(byte dhcpHtype) {
        byte[] htype = BitBufferHelper.toByteArray(dhcpHtype);
        fieldValues.put(HTYPE, htype);
        return this;
    }

    public DHCP setHlen(byte dhcpHlen) {
        byte[] hlen = BitBufferHelper.toByteArray(dhcpHlen);
        fieldValues.put(HLEN, hlen);
        return this;
    }

    public DHCP setHops(byte dhcpHops) {
        byte[] hops = BitBufferHelper.toByteArray(dhcpHops);
        fieldValues.put(HOPS, hops);
        return this;
    }

    public DHCP setXid(int dhcpXid) {
        byte[] xid = BitBufferHelper.toByteArray(dhcpXid);
        fieldValues.put(XID, xid);
        return this;
    }

    public DHCP setSecs(short dhcpSecs) {
        byte[] secs = BitBufferHelper.toByteArray(dhcpSecs);
        fieldValues.put(SECS, secs);
        return this;
    }

    public DHCP setFlags(short dhcpFlags) {
        byte[] flags = BitBufferHelper.toByteArray(dhcpFlags);
        fieldValues.put(FLAGS, flags);
        return this;
    }

    public DHCP setCiaddr(byte[] ciaddr) {
        fieldValues.put(CIADDR, ciaddr);
        return this;
    }

    public DHCP setCiaddr(int dhcpCiaddr) {
        byte[] ciaddr = BitBufferHelper.toByteArray(dhcpCiaddr);
        fieldValues.put(CIADDR, ciaddr);
        return this;
    }

    public DHCP setCiaddr(InetAddress dhcpCiaddr) {
        byte[] ciaddr = dhcpCiaddr.getAddress();
        fieldValues.put(CIADDR, ciaddr);
        return this;
    }

    public DHCP setCiaddr(String dhcpCiaddr) {
        byte[] ciaddr = NetUtils.parseInetAddress(dhcpCiaddr).getAddress();
        fieldValues.put(CIADDR, ciaddr);
        return this;
    }

    public DHCP setYiaddr(byte[] yiaddr) {
        fieldValues.put(YIADDR, yiaddr);
        return this;
    }

    public DHCP setYiaddr(int dhcpYiaddr) {
        byte[] yiaddr = BitBufferHelper.toByteArray(dhcpYiaddr);
        fieldValues.put(YIADDR, yiaddr);
        return this;
    }

    public DHCP setYiaddr(InetAddress dhcpYiaddr) {
        byte[] yiaddr = dhcpYiaddr.getAddress();
        fieldValues.put(YIADDR, yiaddr);
        return this;
    }

    public DHCP setYiaddr(String dhcpYiaddr) {
        byte[] yiaddr = NetUtils.parseInetAddress(dhcpYiaddr).getAddress();
        fieldValues.put(YIADDR, yiaddr);
        return this;
    }

    public DHCP setSiaddr(byte[] siaddr) {
        fieldValues.put(SIADDR, siaddr);
        return this;
    }

    public DHCP setSiaddr(int dhcpSiaddr) {
        byte[] siaddr = BitBufferHelper.toByteArray(dhcpSiaddr);
        fieldValues.put(SIADDR, siaddr);
        return this;
    }

    public DHCP setSiaddr(InetAddress dhcpSiaddr) {
        byte[] siaddr = dhcpSiaddr.getAddress();
        fieldValues.put(SIADDR, siaddr);
        return this;
    }

    public DHCP setSiaddr(String dhcpSiaddr) {
        byte[] siaddr = NetUtils.parseInetAddress(dhcpSiaddr).getAddress();
        fieldValues.put(SIADDR, siaddr);
        return this;
    }

    public DHCP setGiaddr(byte[] giaddr) {
        fieldValues.put(GIADDR, giaddr);
        return this;
    }

    public DHCP setGiaddr(int dhcpGiaddr) {
        byte[] giaddr = BitBufferHelper.toByteArray(dhcpGiaddr);
        fieldValues.put(GIADDR, giaddr);
        return this;
    }

    public DHCP setGiaddr(InetAddress dhcpGiaddr) {
        byte[] giaddr = dhcpGiaddr.getAddress();
        fieldValues.put(GIADDR, giaddr);
        return this;
    }

    public DHCP setGiaddr(String dhcpGiaddr) {
        byte[] giaddr = NetUtils.parseInetAddress(dhcpGiaddr).getAddress();
        fieldValues.put(GIADDR, giaddr);
        return this;
    }

    public DHCP setChaddr(byte[] chaddr) {
        fieldValues.put(CHADDR, chaddr);
        return this;
    }

    public DHCP setSname(byte[] sname) {
        fieldValues.put(SNAME, sname);
        return this;
    }

    public DHCP setFile(byte[] file) {
        fieldValues.put(FILE, file);
        return this;
    }

    public DHCP setMcookie(int dhcpMc) {
        byte[] mc = BitBufferHelper.toByteArray(dhcpMc);
        fieldValues.put(MCOOKIE, mc);
        return this;
    }

    public DHCP setOptions(byte[] options) {
        fieldValues.put(OPTIONS, options);
        return this;
    }

    //    public void setPadding(byte[] pad) {
    //        this.pad = pad;
    //    }

    /**
     * This method deserializes the data bits obtained from the wire into the
     * respective header and payload which are of type Packet.
     *
     * @param data       byte[] data from wire to deserialize
     * @param bitOffset  int    bit position where packet header starts in data
     *        array
     * @param size       int    size of packet in bits
     * @return Packet
     * @throws PacketException the packet deserialization failed
     *
     * <p>Note: Copied from org.opendaylight.controller.sal.packet.Packet</p>
     */
    @Override
    public Packet deserialize(byte[] data, int bitOffset, int size) throws PacketException {

        // Deserialize the header fields one by one
        int startOffset = 0;
        int numBits = 0;
        for (Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap.entrySet()) {
            String hdrField = pairs.getKey();
            startOffset = bitOffset + this.getfieldOffset(hdrField);
            if (hdrField.equals(OPTIONS)) {
                numBits = (size - DHCP_NOOPT_HDR_SIZE) * 8;
            } else {
                numBits = this.getfieldnumBits(hdrField);
            }
            byte[] hdrFieldBytes = null;
            try {
                hdrFieldBytes = BitBufferHelper.getBits(data, startOffset, numBits);
            } catch (BufferException e) {
                throw new PacketException(e.getMessage());
            }

            /*
             * Store the raw read value, checks the payload type and set the
             * payloadClass accordingly
             */
            this.setHeaderField(hdrField, hdrFieldBytes);

            if (LOG.isTraceEnabled()) {
                LOG.trace("{}: {}: {} (offset {} bitsize {})", this.getClass().getSimpleName(), hdrField,
                        HexEncode.bytesToHexString(hdrFieldBytes), startOffset, numBits);
            }
        }

        // Deserialize the payload now
        int payloadStart = startOffset + numBits;
        int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart;

        if (payloadClass != null) {
            try {
                payload = payloadClass.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException("Error parsing payload for Ethernet packet", e);
            }
            payload.deserialize(data, payloadStart, payloadSize);
            payload.setParent(this);
        } else {
            /*
             *  The payload class was not set, it means no class for parsing
             *  this payload is present. Let's store the raw payload if any.
             */
            int start = payloadStart / NetUtils.NumBitsInAByte;
            int stop = start + payloadSize / NetUtils.NumBitsInAByte;
            rawPayload = Arrays.copyOfRange(data, start, stop);
        }
        // Take care of computation that can be done only after deserialization
        postDeserializeCustomOperation(data, payloadStart - getHeaderSize());

        return this;
    }

    @Override
    public byte[] serialize() throws PacketException {
        this.setOptions(this.dhcpOptions.serialize());
        byte[] data = super.serialize();
        // Check for OPT_END at end of options
        if (data.length > DHCP_MAX_SIZE) {
            // shouldn't have happened
            // Add exception?
            LOG.error("DHCP Packet too big");
        } else if (data[data.length - 1] != (byte) 255) {
            // DHCP Options not ended properly
            //throw new PacketException("Missing DHCP Option END");
            LOG.error("Missing DHCP Option END");
        } else if (data.length < DHCP_MIN_SIZE) {
            byte[] padding = new byte[DHCP_MIN_SIZE - data.length];
            LOG.debug("DHCP Pkt too small: {}, padding added {}", data.length, padding.length);
            data = ArrayUtils.addAll(data, padding);
        }
        return data;
    }

    @Override
    /**
     * Gets the number of bits for the fieldname specified
     * If the fieldname has variable length like "Options", then this value is computed using the header length
     * @param fieldname - String
     * @return number of bits for fieldname - int
     */
    public int getfieldnumBits(String fieldName) {
        if (fieldName.equals(OPTIONS)) {
            byte[] barr = fieldValues.get(OPTIONS);
            return (barr.length) * NetUtils.NumBitsInAByte;
        }
        return hdrFieldCoordMap.get(fieldName).getRight();
    }

    @Override
    public int getHeaderSize() {
        byte[] barr = fieldValues.get(OPTIONS);
        int len = 0;
        if (barr != null) {
            len = barr.length;
        }
        return (DHCP_NOOPT_HDR_SIZE + len) * 8;
    }

    @Override
    protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) {
        //TODO: Anything need to be done here?
        // Check for MAGIC_COOKIE. This means we only support DHCP, not BOOTP
        int cookie = BitBufferHelper.getInt(fieldValues.get(MCOOKIE));
        if (cookie != MAGIC_COOKIE) {
            LOG.debug("Not DHCP packet");
            // Throw exception?
        }
        // parse options into DHCPOptions
        this.dhcpOptions.deserialize(this.getOptions());
        // reset options byte array, this will also drop padding
        this.setOptions(this.dhcpOptions.serialize());
    }

    // Set/get operations for Options
    public void setMsgType(byte type) {
        dhcpOptions.setOptionByte(OPT_MESSAGE_TYPE, type);
    }

    public byte getMsgType() {
        return dhcpOptions.getOptionByte(OPT_MESSAGE_TYPE);
    }

    public void setOptionByte(byte code, byte opt) {
        dhcpOptions.setOptionByte(code, opt);
    }

    public byte getOptionByte(byte code) {
        return dhcpOptions.getOptionByte(code);
    }

    public void setOptionBytes(byte code, byte[] opt) {
        dhcpOptions.setOption(code, opt);
    }

    public byte[] getOptionBytes(byte code) {
        return dhcpOptions.getOptionBytes(code);
    }

    public void setOptionShort(byte code, short opt) {
        dhcpOptions.setOptionShort(code, opt);
    }

    public short getOptionShort(byte code) {
        return dhcpOptions.getOptionShort(code);
    }

    public void setOptionInt(byte code, int opt) {
        dhcpOptions.setOptionInt(code, opt);
    }

    public int getOptionInt(byte code) {
        return dhcpOptions.getOptionInt(code);
    }

    public InetAddress getOptionInetAddr(byte code) {
        return dhcpOptions.getOptionInetAddr(code);
    }

    public void setOptionInetAddr(byte code, InetAddress addr) {
        dhcpOptions.setOptionInetAddr(code, addr);
    }

    public void setOptionInetAddr(byte code, String addr) throws UnknownHostException {
        dhcpOptions.setOptionStrAddr(code, addr);
    }

    public String getOptionStrAddr(byte code) {
        return dhcpOptions.getOptionStrAddr(code);
    }

    public void setOptionStrAddrs(byte code, List<String> opt) throws UnknownHostException {
        dhcpOptions.setOptionStrAddrs(code, opt);
    }

    public void setOptionString(byte code, String str) {
        dhcpOptions.setOptionString(code, str);
    }

    public boolean containsOption(byte code) {
        // TODO Auto-generated method stub
        return dhcpOptions.containsOption(code);
    }

    public void unsetOption(byte code) {
        dhcpOptions.unsetOption(code);
    }

    @Override
    public String toString() {
        StringBuilder ret = new StringBuilder();
        ret.append(super.toString()).append(dhcpOptions);

        return ret.toString();
    }
}