/*******************************************************************************
* Copyright (c) 2011, 2016 Eurotech and/or its affiliates
*
* 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
*
* Contributors:
* Eurotech
*******************************************************************************/
package org.eclipse.kura.net;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.kura.KuraErrorCode;
import org.eclipse.kura.KuraException;
/**
* Base class for configuration of network interfaces.
* The two subclasses NetConfigIP4 and NetConfigIP6 represent
* configurations of IPv4 and IPv6 addresses respectively.
*
* @param <T>
* IPv4 or IPv6 address
*/
public abstract class NetConfigIP<T extends IPAddress> implements NetConfig {
private NetInterfaceStatus m_status;
private boolean m_autoConnect;
private boolean m_dhcp;
private T m_address;
private short m_networkPrefixLength;
private T m_subnetMask;
private T m_gateway;
private List<T> m_dnsServers;
private List<String> m_domains;
private Map<String, Object> m_properties;
NetConfigIP(NetInterfaceStatus status, boolean autoConnect) {
this.m_status = status;
this.m_autoConnect = autoConnect;
this.m_dhcp = false;
this.m_address = null;
this.m_networkPrefixLength = -1;
this.m_subnetMask = null;
this.m_gateway = null;
this.m_dnsServers = new ArrayList<T>();
this.m_domains = new ArrayList<String>();
this.m_properties = new HashMap<String, Object>();
}
NetConfigIP(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) {
this.m_status = status;
this.m_autoConnect = autoConnect;
this.m_dhcp = dhcp;
this.m_address = null;
this.m_networkPrefixLength = -1;
this.m_subnetMask = null;
this.m_gateway = null;
this.m_dnsServers = new ArrayList<T>();
this.m_domains = new ArrayList<String>();
this.m_properties = new HashMap<String, Object>();
}
NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, short networkPrefixLength, T gateway)
throws KuraException {
this.m_status = status;
this.m_autoConnect = autoConnect;
this.m_dhcp = false;
this.m_address = address;
this.m_networkPrefixLength = networkPrefixLength;
this.m_subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength);
this.m_gateway = gateway;
this.m_dnsServers = new ArrayList<T>();
this.m_domains = new ArrayList<String>();
this.m_properties = new HashMap<String, Object>();
}
NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, T subnetMask, T gateway)
throws KuraException {
this.m_status = status;
this.m_autoConnect = autoConnect;
this.m_dhcp = false;
this.m_address = address;
this.m_networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress());
this.m_subnetMask = subnetMask;
this.m_gateway = gateway;
this.m_dnsServers = new ArrayList<T>();
this.m_domains = new ArrayList<String>();
this.m_properties = new HashMap<String, Object>();
}
/**
* Return the NetInterfaceStatus of this configuration
*
* @return
*/
public NetInterfaceStatus getStatus() {
return this.m_status;
}
/**
* Sets the NetInterfaceStatus to be used for the network interface
*
* @param status
*/
public void setStatus(NetInterfaceStatus status) {
this.m_status = status;
}
public boolean isAutoConnect() {
return this.m_autoConnect;
}
public void setAutoConnect(boolean autoConnect) {
this.m_autoConnect = autoConnect;
}
public boolean isDhcp() {
return this.m_dhcp;
}
/**
* Sets whether of not this configuration should be a dhcp client. If dhcp
* is set to true it overrides and static configuration that is present in
* the configuration.
*
* @param dhcp
* whether or not dhcp client mode should be used
*/
public void setDhcp(boolean dhcp) {
this.m_dhcp = dhcp;
}
/**
* Returns the address that should be statically assigned to the interface.
* The returned address is IP4Address or IP6Address depending on
* the NetConfigIP instance used. This is only used if dhcp is set to false.
*
* @return the static address for the interface
*/
public T getAddress() {
return this.m_address;
}
/**
* Sets the static address to be assigned to the interface.
* The address should IP4Address or IP6Address depending on
* the NetConfigIP instance used. This is only used if dhcp is set to false.
*
* @param address
* - address to be statically assigned to the interface
*/
public void setAddress(T address) throws KuraException {
this.m_address = address;
}
/**
* Return the prefix to be used for the network interface
*
* @return
*/
public short getNetworkPrefixLength() {
return this.m_networkPrefixLength;
}
/**
* Sets the prefix length to be used for the network interface
*
* @param networkPrefixLength
* @throws KuraException
*/
public void setNetworkPrefixLength(short networkPrefixLength) throws KuraException {
this.m_networkPrefixLength = networkPrefixLength;
this.m_subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength);
}
/**
* Return the prefix to be used for the network interface
*
* @return
*/
public T getSubnetMask() {
return this.m_subnetMask;
}
/**
* Sets the subnet mask to be used for the network interface
*
* @param subnetMask
* @throws KuraException
*/
public void setSubnetMask(T subnetMask) throws KuraException {
this.m_networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress());
this.m_subnetMask = subnetMask;
}
/**
* Returns the address of the gateway to be used for the interface
*
* @return
*/
public T getGateway() {
return this.m_gateway;
}
/**
* Sets the gateway to be used for the interface
*
* @param gateway
*/
public void setGateway(T gateway) {
this.m_gateway = gateway;
}
/**
* Returns the list of Name Servers to be associated to the interface.
* The returned addresses are IP4Address or IP6Address depending on
* the NetConfigIP instance used. This is only used if dhcp is set to false.
*
* @return list of address for the DNS Servers
*/
public List<T> getDnsServers() {
if (this.m_dnsServers != null) {
return Collections.unmodifiableList(this.m_dnsServers);
} else {
return null;
}
}
/**
* Sets the list of Name Servers to be associated to the interface.
* The addresses are IP4Address or IP6Address depending on
* the NetConfigIP instance used. This is only used if dhcp is set to false.
*/
public void setDnsServers(List<T> dnsServers) {
this.m_dnsServers = dnsServers;
}
/**
* Returns the list of DNS domains to be associated to the interface.
* This is only used if dhcp is set to false.
*
* @return - list of DNS domains
*/
public List<String> getDomains() {
if (this.m_domains != null) {
return Collections.unmodifiableList(this.m_domains);
} else {
return null;
}
}
/**
* Sets the list of DNS domains to be associated to the interface.
* This is only used if dhcp is set to false.
*
* @param domains
*/
public void setDomains(List<String> domains) {
this.m_domains = domains;
}
public Map<String, Object> getProperties() {
if (this.m_properties != null) {
return Collections.unmodifiableMap(this.m_properties);
} else {
return null;
}
}
public void setProperties(Map<String, Object> properties) {
this.m_properties = properties;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (this.m_address == null ? 0 : this.m_address.hashCode());
result = prime * result + (this.m_autoConnect ? 1231 : 1237);
result = prime * result + (this.m_dhcp ? 1231 : 1237);
result = prime * result + (this.m_dnsServers == null ? 0 : this.m_dnsServers.hashCode());
result = prime * result + (this.m_domains == null ? 0 : this.m_domains.hashCode());
result = prime * result + (this.m_gateway == null ? 0 : this.m_gateway.hashCode());
result = prime * result + this.m_networkPrefixLength;
result = prime * result + (this.m_properties == null ? 0 : this.m_properties.hashCode());
result = prime * result + (this.m_status == null ? 0 : this.m_status.hashCode());
result = prime * result + (this.m_subnetMask == null ? 0 : this.m_subnetMask.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
@SuppressWarnings("rawtypes")
NetConfigIP other = (NetConfigIP) obj;
if (this.m_address == null) {
if (other.m_address != null) {
return false;
}
} else if (!this.m_address.equals(other.m_address)) {
return false;
}
if (this.m_autoConnect != other.m_autoConnect) {
return false;
}
if (this.m_dhcp != other.m_dhcp) {
return false;
}
if (this.m_dnsServers == null) {
if (other.m_dnsServers != null) {
return false;
}
} else if (!this.m_dnsServers.equals(other.m_dnsServers)) {
return false;
}
if (this.m_domains == null) {
if (other.m_domains != null) {
return false;
}
} else if (!this.m_domains.equals(other.m_domains)) {
return false;
}
if (this.m_gateway == null) {
if (other.m_gateway != null) {
return false;
}
} else if (!this.m_gateway.equals(other.m_gateway)) {
return false;
}
if (this.m_networkPrefixLength != other.m_networkPrefixLength) {
return false;
}
if (this.m_properties == null) {
if (other.m_properties != null) {
return false;
}
} else if (!this.m_properties.equals(other.m_properties)) {
return false;
}
if (this.m_status != other.m_status) {
return false;
}
if (this.m_subnetMask == null) {
if (other.m_subnetMask != null) {
return false;
}
} else if (!this.m_subnetMask.equals(other.m_subnetMask)) {
return false;
}
return true;
}
@Override
public boolean isValid() {
// FIXME
if (this.m_dhcp) {
return true;
} else {
try {
this.m_address.getHostAddress();
} catch (Exception e) {
e.printStackTrace();
return false;
}
for (IPAddress dns : this.m_dnsServers) {
try {
dns.getHostAddress();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// if we got here...
return true;
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("NetConfigIP [m_status=");
builder.append(this.m_status);
builder.append(", m_autoConnect=");
builder.append(this.m_autoConnect);
builder.append(", m_dhcp=");
builder.append(this.m_dhcp);
builder.append(", m_address=");
builder.append(this.m_address);
builder.append(", m_networkPrefixLength=");
builder.append(this.m_networkPrefixLength);
builder.append(", m_subnetMask=");
builder.append(this.m_subnetMask);
builder.append(", m_gateway=");
builder.append(this.m_gateway);
builder.append(", m_dnsServers=");
builder.append(this.m_dnsServers);
builder.append(", m_domains=");
builder.append(this.m_domains);
builder.append(", m_properties=");
builder.append(this.m_properties);
builder.append("]");
return builder.toString();
}
// TODO - only works on IPv4 now
private short calculateNetworkPrefixFromNetmask(String netmask) throws KuraException {
if (netmask == null) {
throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "netmask is null");
}
int netmaskValue = 0;
StringTokenizer st = new StringTokenizer(netmask, ".");
for (int i = 24; i >= 0; i -= 8) {
netmaskValue = netmaskValue | Integer.parseInt(st.nextToken()) << i;
}
boolean hitZero = false;
int displayMask = 1 << 31;
int count = 0;
for (int c = 1; c <= 32; c++) {
if ((netmaskValue & displayMask) == 0) {
hitZero = true;
} else {
if (hitZero) {
throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "received invalid mask: " + netmask);
}
count++;
}
netmaskValue <<= 1;
}
return (short) count;
}
// TODO - only works on IPv4 now
private T calculateNetmaskFromNetworkPrefix(int networkPrefixLength) throws KuraException {
int mask = ~((1 << 32 - networkPrefixLength) - 1);
StringBuffer sb = new StringBuffer(15);
for (int shift = 24; shift > 0; shift -= 8) {
// process 3 bytes, from high order byte down.
sb.append(Integer.toString(mask >>> shift & 0xff));
sb.append('.');
}
sb.append(Integer.toString(mask & 0xff));
try {
@SuppressWarnings("unchecked")
T netmask = (T) IPAddress.parseHostAddress(sb.toString());
return netmask;
} catch (UnknownHostException e) {
throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e);
}
}
}