/**************************************************************************
* Parts copyright (c) 2005, 2009, 2016 by Chris Gray, KIFFER Ltd. *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* 3. Neither the name of KIFFER Ltd nor the names of other contributors *
* may be used to endorse or promote products derived from this *
* software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
* IN NO EVENT SHALL KIFFER LTD OR OTHER CONTRIBUTORS BE LIABLE FOR ANY *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE *
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER *
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR *
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
**************************************************************************/
package java.net;
import java.io.Serializable;
import java.util.StringTokenizer;
public final class Inet4Address extends InetAddress implements Serializable {
/**
** creates an empty InetAddress used by peek
*/
Inet4Address(){}
/**
** Create an InetAddress object with the given fields.
** If ttl > 0 an entry will also be created in the address cache.
** @param ip The IP address in integer form
** @param name The hostname
** @param ipname The IP address in dotted-string form
** @param ttl The time-to-live, in seconds
*/
Inet4Address(int ip, String name, String ipname, int ttl){
address = ip;
family = InetAddress.TYPE_IPV4;
hostName = name;
ipAddressString = ipname.toLowerCase();
if (name != null && ttl > 0) {
long expiry = System.currentTimeMillis() + (1000L * ttl);
synchronized(positive_cache){
positive_cache.put(name, new IAddrCacheEntry(this, expiry));
positive_cache.put(ipAddressString, new IAddrCacheEntry(this, expiry));
}
}
}
/**
** Create an InetAddress object with the given fields.
** If ttl > 0 an entry will also be created in the address cache.
** @param ipAddress The binary IP address
** @param hostname The hostname
** @param ttl The time-to-live, in seconds
*/
Inet4Address(byte[] ipAddress, String hostname, int ttl) throws UnknownHostException {
this( (((((((ipAddress[0] << 8) | ipAddress[1]) << 8) | ipAddress[2]) << 8) | ipAddress[3]) << 8),
hostname,
(ipAddress[0] & 0xff) + "." + (ipAddress[1] & 0xff) + "." + (ipAddress[2] & 0xff) + "." + (ipAddress[3] & 0xff),
ttl
);
}
/**
** Create an InetAddress object with the given fields.
** If ttl > 0 an entry will also be created in the address cache.
** @param name The hostname
** @param ttl The time-to-live, in seconds
*/
Inet4Address(String name, int ttl) throws UnknownHostException {
int char0 = name.charAt(0);
if(char0 >= '0' && char0 <= '9'){
StringTokenizer s = new StringTokenizer(name,".");
if(s.countTokens() == 4){
try {
for(int i = 0 ; i < 4 ; i++){
int octet = Integer.parseInt(s.nextToken());
if(octet < 0 || octet > 255){
throw new UnknownHostException();
}
address = octet + (address<<8);
}
}
catch(NumberFormatException nfe){
throw new UnknownHostException();
}
}
family = InetAddress.TYPE_IPV4;
if (ttl > 0) {
long expiry = System.currentTimeMillis() + (1000L * ttl);
synchronized(positive_cache){
positive_cache.put(getHostAddress(), new IAddrCacheEntry(this, expiry));
positive_cache.put(name, new IAddrCacheEntry(this, expiry));
}
}
}
else {
createInetAddress(name);
if (ttl > 0) {
long expiry = System.currentTimeMillis() + (1000L * ttl);
synchronized(positive_cache){
// We cache this under both the requested name and the canonical name
positive_cache.put(name, new IAddrCacheEntry(this, expiry));
positive_cache.put(this.getHostName(), new IAddrCacheEntry(this, expiry));
positive_cache.put(this.getHostAddress(), new IAddrCacheEntry(this, expiry));
}
}
}
}
public byte[] getAddress() {
byte[] octets = new byte[4];
octets[3] = (byte)address;
octets[2] = (byte)(address>>>8);
octets[1] = (byte)(address>>>16);
octets[0] = (byte)(address>>>24);
return octets;
}
public boolean isMulticastAddress () {
final int firstByte = getAddress()[0] & 0xff;
return firstByte > 223 && firstByte < 240;
}
public boolean isAnyLocalAddress() {
return address == 0;
}
public boolean isLinkLocalAddress() {
// According to the Android sources:
// The reference implementation does not return true for loopback
// addresses even though RFC 3484 says to do so
final byte[] bytes = getAddress();
final int firstByte = bytes[0] & 0xff;
final int secondByte = bytes[1] & 0xff;
return firstByte == 169 && secondByte == 254;
}
public boolean isLoopbackAddress() {
byte[] ip = getAddress();
return ip[0] == 127;
}
public boolean isMCGlobal() {
if (!isMulticastAddress()) {
return false;
}
byte[] ip = getAddress();
switch(ip[0]) {
// must be 0xe0 -- 0xef or isMulticastAddress() would have returned false
case (byte) 0xe0:
return !(ip[1] == 0 && ip[2] == 0);
case (byte) 0xef:
return false;
default:
return true;
}
}
public boolean isMCLinkLocal() {
byte[] ip = getAddress();
return ip[0] == 0xe0 && ip[1] == 00 && ip[2] == 0;
}
public boolean isMCOrgLocal() {
byte[] ip = getAddress();
return ip[0] == 0xef && (ip[1] & 0xfc) == 0xc0;
}
public boolean isMCSiteLocal() {
byte[] ip = getAddress();
return ip[0] == 0xef && ip[1] == 0xff;
}
public boolean isSiteLocalAddress() {
final byte[] bytes = getAddress();
final int firstByte = bytes[0] & 0xff;
final int secondByte = bytes[1] & 0xff;
// 10/8
if (firstByte == 10) {
return true;
}
// 172.16/12
if (firstByte == 172 && (secondByte & 0xf0) == 0x10) {
return true;
}
// 192.168/16
if (firstByte == 192 && secondByte == 168) {
return true;
}
return false;
}
}