5f2f3e101d2c24950465422a1f70257bc605cdce
[netvirt.git] / vpnservice / dhcpservice / dhcpservice-api / src / main / java / org / opendaylight / netvirt / dhcpservice / api / DHCPOptions.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.dhcpservice.api;
10
11 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.OPT_END;
12 import static org.opendaylight.netvirt.dhcpservice.api.DHCPConstants.OPT_PAD;
13
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.nio.charset.StandardCharsets;
18 import java.util.LinkedHashMap;
19 import java.util.List;
20 import org.apache.commons.lang3.ArrayUtils;
21 import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
22 import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
23
24 public class DHCPOptions {
25
26     private static class DhcpOption {
27         private byte code;
28         private byte length;
29         private byte[] value;
30
31         DhcpOption(byte code, byte[] value) {
32             if (code != OPT_PAD && code != OPT_END && value != null) {
33                 this.code = code;
34                 this.value = value;
35                 this.length = (byte) value.length;
36             }
37         }
38
39         public byte getCode() {
40             return this.code;
41         }
42
43         public byte[] getValue() {
44             return this.value;
45         }
46
47         public byte[] serialize() {
48             byte[] opt1 = new byte[2];
49             opt1[0] = this.code;
50             opt1[1] = this.length;
51             return ArrayUtils.addAll(opt1, this.value);
52         }
53
54         @Override
55         public String toString() {
56             StringBuilder sb = new StringBuilder();
57             sb.append("{ ")
58                     .append("code: ").append(this.code)
59                     .append(", len: ").append(this.length)
60                     .append(", value: 0x").append(HexEncode.bytesToHexString(this.value))
61                     .append(" }");
62             return sb.toString();
63         }
64     }
65
66     private final LinkedHashMap<Byte, DhcpOption> options;
67
68     public DHCPOptions() {
69         options = new LinkedHashMap<>();
70     }
71
72     private DhcpOption getOption(byte code) {
73         return this.options.get(code);
74     }
75
76     private void setOption(DhcpOption opt) {
77         this.options.put(opt.getCode(), opt);
78     }
79
80     public void setOption(byte code, byte[] opt) {
81         this.setOption(new DhcpOption(code, opt));
82     }
83
84     // It's unclear from all the callers if returning an empty array would be safe.
85     @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS")
86     public byte[] getOptionBytes(byte code) {
87         DhcpOption option = this.getOption(code);
88         return option != null ? option.getValue() : null;
89     }
90
91     public void setOptionByte(byte code, byte opt) {
92         this.setOption(new DhcpOption(code, DHCPUtils.byteToByteArray(opt)));
93     }
94
95     public byte getOptionByte(byte code) {
96         return this.getOption(code).getValue()[0];
97     }
98
99     public void setOptionShort(byte code, short opt) {
100         this.setOption(new DhcpOption(code, DHCPUtils.shortToByteArray(opt)));
101     }
102
103     public short getOptionShort(byte code) {
104         byte[] opt = this.getOptionBytes(code);
105         return DHCPUtils.byteArrayToShort(opt);
106     }
107
108     public void setOptionInt(byte code, int opt) {
109         this.setOption(new DhcpOption(code, DHCPUtils.intToByteArray(opt)));
110     }
111
112     public int getOptionInt(byte code) {
113         byte[] opt = this.getOptionBytes(code);
114         return NetUtils.byteArray4ToInt(opt);
115     }
116
117     public void setOptionInetAddr(byte code, InetAddress opt) {
118         this.setOption(new DhcpOption(code, DHCPUtils.inetAddrToByteArray(opt)));
119     }
120
121     public InetAddress getOptionInetAddr(byte code) {
122         byte[] opt = this.getOptionBytes(code);
123         try {
124             return InetAddress.getByAddress(opt);
125         } catch (UnknownHostException | NullPointerException e) {
126             return null;
127         }
128     }
129
130     public void setOptionStrAddr(byte code, String opt) throws UnknownHostException {
131         this.setOption(new DhcpOption(code, DHCPUtils.strAddrToByteArray(opt)));
132     }
133
134     public String getOptionStrAddr(byte code) {
135         byte[] opt = this.getOptionBytes(code);
136         try {
137             return InetAddress.getByAddress(opt).getHostAddress();
138         } catch (UnknownHostException | NullPointerException e) {
139             return null;
140         }
141     }
142
143     public void setOptionStrAddrs(byte code, List<String> addrs) throws UnknownHostException {
144         if (!addrs.isEmpty()) {
145             this.setOption(new DhcpOption(code, DHCPUtils.strListAddrsToByteArray(addrs)));
146         }
147     }
148
149     public void setOptionString(byte code, String str) {
150         this.setOption(new DhcpOption(code, str.getBytes(StandardCharsets.UTF_8)));
151     }
152
153     public byte[] serialize() {
154         byte[] serializedOptions = new byte[0];
155         for (DhcpOption dhcpOption: this.options.values()) {
156             serializedOptions = ArrayUtils.addAll(serializedOptions, dhcpOption.serialize());
157         }
158         byte[] end = new byte[] {(byte)255};
159         serializedOptions = ArrayUtils.addAll(serializedOptions, end);
160         return serializedOptions;
161     }
162
163     private byte[] getOptionValArray(byte[] opt, int pos, int len) {
164         byte[] val = new byte[len];
165         for (int i = 0; i < len; i++) {
166             val[i] = opt[pos + i];
167         }
168         return val;
169     }
170
171     public void deserialize(byte[] serializedOptions) {
172         int pos = 0;
173         byte code;
174         byte len;
175         byte[] value;
176         if (serializedOptions != null) {
177             while (pos < serializedOptions.length) {
178                 code = serializedOptions[pos++];
179                 if (code == OPT_END) {
180                     break;
181                 }
182                 len = serializedOptions[pos++];
183                 if (len + pos > serializedOptions.length) {
184                     // Throw exception???
185                     break;
186                 }
187                 value = getOptionValArray(serializedOptions, pos, len);
188                 setOption(code, value);
189                 pos += len;
190             }
191         }
192     }
193
194     @Override
195     public String toString() {
196         StringBuilder sb = new StringBuilder();
197         sb.append("{");
198         int count = 1;
199         for (DhcpOption dhcpOption: this.options.values()) {
200             //options = ArrayUtils.addAll(options, dOpt.serialize());
201             sb.append("Option").append(count++).append(dhcpOption.toString());
202         }
203         sb.append("}");
204         return sb.toString();
205     }
206
207     public boolean containsOption(byte code) {
208         return options.containsKey(code);
209     }
210
211     public DhcpOption unsetOption(byte code) {
212         return options.remove(code);
213     }
214
215 }
216