📄 dhcpoption.java
字号:
/*
* This file is part of dhcp4java, a DHCP API for the Java language.
* (c) 2006 Stephan Hadinger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.dhcp4java;
import static org.dhcp4java.DHCPConstants.*;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Class for manipulating DHCP options (used internally).
*
* @author Stephan Hadinger
* @version 1.00
*
* Immutable object.
*/
public class DHCPOption implements Serializable {
private static final long serialVersionUID = 2L;
private static final Logger logger = Logger.getLogger(DHCPOption.class.getName().toLowerCase());
/**
* The code of the option. 0 is reserved for padding, -1 for end of options.
*/
private final byte code;
/**
* Raw bytes value of the option. Some methods are provided for higher
* level of data structures, depending on the <tt>code</tt>.
*/
private final byte[] value;
/**
* Used to mark an option as having a mirroring behaviour. This means that
* this option if used by a server will first mirror the option the client sent
* then provide a default value if this option was not present in the request.
*
* <p>This is only meant to be used by servers through the <tt>getMirrorValue</tt>
* method.
*/
private final boolean mirror;
/**
* Constructor for <tt>DHCPOption</tt>.
*
* <p>Note: you must not prefix the value by a length-byte. The length prefix
* will be added automatically by the API.
*
* <p>If value is <tt>null</tt> it is considered as an empty option.
* If you add an empty option to a DHCPPacket, it removes the option from the packet.
*
* <p>This constructor adds a parameter to mark the option as "mirror". See comments above.
*
* @param code DHCP option code
* @param value DHCP option value as a byte array.
*/
public DHCPOption(byte code, byte[] value, boolean mirror) {
if (code == DHO_PAD) {
throw new IllegalArgumentException("code=0 is not allowed (reserved for padding");
}
if (code == DHO_END) {
throw new IllegalArgumentException("code=-1 is not allowed (reserved for End Of Options)");
}
this.code = code;
this.value = (value != null) ? value.clone() : null;
this.mirror = mirror;
}
/**
* Constructor for <tt>DHCPOption</tt>. This is the default constructor.
*
* <p>Note: you must not prefix the value by a length-byte. The length prefix
* will be added automatically by the API.
*
* <p>If value is <tt>null</tt> it is considered as an empty option.
* If you add an empty option to a DHCPPacket, it removes the option from the packet.
*
* @param code DHCP option code
* @param value DHCP option value as a byte array.
*/
public DHCPOption(byte code, byte[] value) {
this(code, value, false);
}
/**
* Return the <tt>code</tt> field (byte).
*
* @return code field
*/
public byte getCode() {
return this.code;
}
/**
* returns true if two <tt>DHCPOption</tt> objects are equal, i.e. have same <tt>code</tt>
* and same <tt>value</tt>.
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof DHCPOption)) {
return false;
}
DHCPOption opt = (DHCPOption) o;
return ((opt.code == this.code) &&
(opt.mirror == this.mirror) &&
Arrays.equals(opt.value, this.value));
}
/**
* Returns hashcode.
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.code ^ Arrays.hashCode(this.value) ^
(this.mirror ? 0x80000000 : 0);
}
/**
*
* @return option value, can be null.
*/
public byte[] getValue() {
return ((this.value == null) ? null : this.value.clone());
}
/**
*
* @return option value, never <tt>null</tt>. Minimal value is <tt>byte[0]</tt>.
*/
public byte[] getValueFast() {
return this.value;
}
/**
* Returns whether the option is marked as "mirror", meaning it should mirror
* the option value in the client request.
*
* <p>To be used only in servers.
*
* @return is the option marked is mirror?
*/
public boolean isMirror() {
return this.mirror;
}
public static final boolean isOptionAsByte(byte code) {
return OptionFormat.BYTE.equals(_DHO_FORMATS.get(code));
}
/**
* Creates a DHCP Option as Byte format.
*
* <p>This method is only allowed for the following option codes:
* <pre>
* DHO_IP_FORWARDING(19)
* DHO_NON_LOCAL_SOURCE_ROUTING(20)
* DHO_DEFAULT_IP_TTL(23)
* DHO_ALL_SUBNETS_LOCAL(27)
* DHO_PERFORM_MASK_DISCOVERY(29)
* DHO_MASK_SUPPLIER(30)
* DHO_ROUTER_DISCOVERY(31)
* DHO_TRAILER_ENCAPSULATION(34)
* DHO_IEEE802_3_ENCAPSULATION(36)
* DHO_DEFAULT_TCP_TTL(37)
* DHO_TCP_KEEPALIVE_GARBAGE(39)
* DHO_NETBIOS_NODE_TYPE(46)
* DHO_DHCP_OPTION_OVERLOAD(52)
* DHO_DHCP_MESSAGE_TYPE(53)
* DHO_AUTO_CONFIGURE(116)
* </pre>
*
* @param code the option code.
* @param val the value
* @throws IllegalArgumentException the option code is not in the list above.
*/
public static DHCPOption newOptionAsByte(byte code, byte val) {
if (!isOptionAsByte(code)) {
throw new IllegalArgumentException("DHCP option type (" + code + ") is not byte");
}
return new DHCPOption(code, byte2Bytes(val));
}
/**
* Returns a DHCP Option as Byte format.
*
* This method is only allowed for the following option codes:
* <pre>
* DHO_IP_FORWARDING(19)
* DHO_NON_LOCAL_SOURCE_ROUTING(20)
* DHO_DEFAULT_IP_TTL(23)
* DHO_ALL_SUBNETS_LOCAL(27)
* DHO_PERFORM_MASK_DISCOVERY(29)
* DHO_MASK_SUPPLIER(30)
* DHO_ROUTER_DISCOVERY(31)
* DHO_TRAILER_ENCAPSULATION(34)
* DHO_IEEE802_3_ENCAPSULATION(36)
* DHO_DEFAULT_TCP_TTL(37)
* DHO_TCP_KEEPALIVE_GARBAGE(39)
* DHO_NETBIOS_NODE_TYPE(46)
* DHO_DHCP_OPTION_OVERLOAD(52)
* DHO_DHCP_MESSAGE_TYPE(53)
* DHO_AUTO_CONFIGURE(116)
* </pre>
*
* @return the option value, <tt>null</tt> if option is not present.
* @throws IllegalArgumentException the option code is not in the list above.
* @throws DHCPBadPacketException the option value in packet is of wrong size.
*/
public byte getValueAsByte() throws IllegalArgumentException {
if (!isOptionAsByte(code)) {
throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not byte");
}
if (this.value == null) {
throw new IllegalStateException("value is null");
}
if (this.value.length != 1) {
throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length + " should be 1");
}
return this.value[0];
}
public static final boolean isOptionAsShort(byte code) {
return OptionFormat.SHORT.equals(_DHO_FORMATS.get(code));
}
/**
* Returns a DHCP Option as Short format.
*
* <p>This method is only allowed for the following option codes:
* <pre>
* DHO_BOOT_SIZE(13)
* DHO_MAX_DGRAM_REASSEMBLY(22)
* DHO_INTERFACE_MTU(26)
* DHO_DHCP_MAX_MESSAGE_SIZE(57)
* </pre>
*
* @return the option value, <tt>null</tt> if option is not present.
* @throws IllegalArgumentException the option code is not in the list above.
* @throws DHCPBadPacketException the option value in packet is of wrong size.
*/
public short getValueAsShort() throws IllegalArgumentException {
if (!isOptionAsShort(code)) {
throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not short");
}
if (this.value == null) {
throw new IllegalStateException("value is null");
}
if (this.value.length != 2) {
throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length + " should be 2");
}
return (short) ((this.value[0] & 0xff) << 8 | (this.value[1] & 0xFF));
}
public static final boolean isOptionAsInt(byte code) {
return OptionFormat.INT.equals(_DHO_FORMATS.get(code));
}
/**
* Returns a DHCP Option as Integer format.
*
* <p>This method is only allowed for the following option codes:
* <pre>
* DHO_TIME_OFFSET(2)
* DHO_PATH_MTU_AGING_TIMEOUT(24)
* DHO_ARP_CACHE_TIMEOUT(35)
* DHO_TCP_KEEPALIVE_INTERVAL(38)
* DHO_DHCP_LEASE_TIME(51)
* DHO_DHCP_RENEWAL_TIME(58)
* DHO_DHCP_REBINDING_TIME(59)
* </pre>
*
* @return the option value, <tt>null</tt> if option is not present.
* @throws IllegalArgumentException the option code is not in the list above.
* @throws DHCPBadPacketException the option value in packet is of wrong size.
*/
public int getValueAsInt() throws IllegalArgumentException {
if (!isOptionAsInt(code)) {
throw new IllegalArgumentException("DHCP option type (" + this.code + ") is not int");
}
if (this.value == null) {
throw new IllegalStateException("value is null");
}
if (this.value.length != 4) {
throw new DHCPBadPacketException("option " + this.code + " is wrong size:" + this.value.length + " should be 4");
}
return ((this.value[0] & 0xFF) << 24 |
(this.value[1] & 0xFF) << 16 |
(this.value[2] & 0xFF) << 8 |
(this.value[3] & 0xFF));
}
// TODO
/**
* Returns a DHCP Option as Integer format, but is usable for any numerical type: int, short or byte.
*
* <p>There is no check on the option
*
* @return the option value <tt>null</tt> if option is not present, or wrong number of bytes.
*/
public Integer getValueAsNum() throws IllegalArgumentException {
if (value == null) {
return null;
}
if (value.length == 1) { // byte
return value[0] & 0xFF;
} else if (value.length == 2) { // short
return ((value[0] & 0xff) << 8 | (value[1] & 0xFF));
} else if (value.length == 4) {
return ((this.value[0] & 0xFF) << 24 |
(this.value[1] & 0xFF) << 16 |
(this.value[2] & 0xFF) << 8 |
(this.value[3] & 0xFF));
} else {
return null;
}
}
public static final boolean isOptionAsInetAddr(byte code) {
return OptionFormat.INET.equals(_DHO_FORMATS.get(code));
}
/**
* Returns a DHCP Option as InetAddress format.
*
* <p>This method is only allowed for the following option codes:
* <pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -