All Downloads are FREE. Search and download functionalities are using the official Maven repository.

inet.ipaddr.ipv4.IPv4Address Maven / Gradle / Ivy

There is a newer version: 5.5.1
Show newest version
package inet.ipaddr.ipv4;

import java.net.Inet4Address;
import java.util.Iterator;

import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressConverter;
import inet.ipaddr.IPAddressSection.IPStringBuilderOptions;
import inet.ipaddr.IPAddressTypeException;
import inet.ipaddr.format.IPAddressPart;
import inet.ipaddr.format.util.IPAddressPartStringCollection;
import inet.ipaddr.ipv4.IPv4AddressNetwork.IPv4AddressCreator;
import inet.ipaddr.ipv4.IPv4AddressSection.IPv4StringBuilderOptions;
import inet.ipaddr.ipv4.IPv4AddressSection.IPv4StringCache;
import inet.ipaddr.ipv4.IPv4AddressSection.IPv4StringCollection;
import inet.ipaddr.ipv6.IPv6Address;
import inet.ipaddr.ipv6.IPv6Address.IPv6AddressConverter;


/**
 * An IPv4 address, or a subnet of multiple IPv4 addresses.
 * 
 * @custom.core
 * @author sfoley
 *
 */
public class IPv4Address extends IPAddress implements Iterable {

	private static final long serialVersionUID = 1L;
	
	public static final char SEGMENT_SEPARATOR = '.';
	public static final int BITS_PER_SEGMENT = 8;
	public static final int BYTES_PER_SEGMENT = 1;
	public static final int SEGMENT_COUNT = 4;
	public static final int BYTE_COUNT = 4;
	public static final int BIT_COUNT = 32;
	public static final int DEFAULT_TEXTUAL_RADIX = 10;
	public static final int MAX_STRING_LEN = 15;
	public static final int MAX_VALUE_PER_SEGMENT = 0xff;
	
	private static IPv4AddressNetwork network = new IPv4AddressNetwork();
	
	/**
	 * Constructs an IPv4 address or subnet.
	 * When networkPrefixLength is non-null, this object represents a network prefix or the set of addresses with the same network prefix (a network or subnet, in other words).
	 * @param segments the address segments
	 * @param networkPrefixLength
	 * @throws IllegalArgumentException if segments is not length 4
	 */
	public IPv4Address(IPv4AddressSegment[] segments, Integer networkPrefixLength) {
		this(network.getAddressCreator().createSection(segments, networkPrefixLength));
	}
	
	/**
	 * Constructs an IPv4 address or subnet.
	 * @param segments the address segments
	 * @throws IllegalArgumentException if segments is not length 4
	 */
	public IPv4Address(IPv4AddressSegment[] segments) {
		this(network.getAddressCreator().createSection(segments));
	}
	
	/**
	 * Constructs an IPv4 address or subnet.
	 * @param section the address segments
	 * @throws IllegalArgumentException if section does not have 4 segments
	 */
	public IPv4Address(IPv4AddressSection section) {
		super(section);
		if(section.getSegmentCount() != SEGMENT_COUNT) {
			throw new IllegalArgumentException();
		}
	}
	
	/**
	 * Constructs an IPv4 address.
	 * 
	 * @param address the 4 byte IPv4 address
	 */
	public IPv4Address(int address) {
		this(address, null);
	}
	
	/**
	 * Constructs an IPv4 address or subnet.
	 * When networkPrefixLength is non-null, this object represents a network prefix or the set of addresses with the same network prefix (a network or subnet, in other words).
	 * 
	 * @param address the 4 byte IPv4 address
	 * @param networkPrefixLength the CIDR network prefix length, which can be null for no prefix
	 */
	public IPv4Address(int address, Integer networkPrefixLength) {
		super(getAddressCreator().createSectionInternal(new byte[] {
				(byte) (address >> 24),
				(byte) ((address >> 16) & 0xff),
				(byte) ((address >> 8) & 0xff),
				(byte) (address & 0xff),
			}, networkPrefixLength));
	}
	
	/**
	 * Constructs an IPv4 address.
	 * 
	 * @param bytes must be a 4 byte IPv4 address
	 * @throws IllegalArgumentException if bytes is not length 4
	 */
	public IPv4Address(byte[] bytes) {
		this(bytes, null);
	}
	
	/**
	 * Constructs an IPv4 address or subnet.
	 * When networkPrefixLength is non-null, this object represents a network prefix or the set of addresses with the same network prefix (a network or subnet, in other words).
	 * 
	 * @param bytes must be a 4 byte IPv4 address
	 * @param networkPrefixLength the CIDR network prefix length, which can be null for no prefix
	 * @throws IllegalArgumentException if bytes is not length 4
	 */
	public IPv4Address(byte[] bytes, Integer networkPrefixLength) {
		super(getAddressCreator().createSection(bytes, networkPrefixLength));
		if(bytes.length != BYTE_COUNT) {
			throw new IllegalArgumentException();
		}
	}

	@Override
	public IPv4AddressSection getSection() {
		return (IPv4AddressSection) super.getSection();
	}

	@Override
	public IPv4AddressSegment getSegment(int index) {
		return getSection().getSegment(index);
	}

	@Override
	public IPAddressPart[] getParts(IPStringBuilderOptions options) {
		return getParts(IPv4StringBuilderOptions.from(options));
	}
	
	public IPAddressPart[] getParts(IPv4StringBuilderOptions options) {
		IPAddressPart parts[] = getSection().getParts(options);
		IPv6Address ipv6Addr = getConverted(options);
		if(ipv6Addr != null) {
			IPAddressPart ipv6Parts[] = ipv6Addr.getParts(options.ipv6ConverterOptions);
			IPAddressPart tmp[] = parts;
			parts = new IPAddressPart[tmp.length + ipv6Parts.length];
			System.arraycopy(tmp, 0, parts, 0, tmp.length);
			System.arraycopy(ipv6Parts,  0, parts, tmp.length, ipv6Parts.length);
		}
		return parts;
	}
	
	@Override
	public int getSegmentCount() {
		return SEGMENT_COUNT;
	}
	
	@Override
	public int getByteCount() {
		return BYTE_COUNT;
	}
	
	@Override
	public int getBitCount() {
		return BIT_COUNT;
	}
	
	@Override
	public IPv4Address toIPv4() {
		return this;
	}
	
	@Override
	public boolean isIPv4Convertible() {
		return true;
	}
	
	public IPv6Address getIPv4MappedAddress() {
		return IPv6Address.toIPv4Mapped(this);
	}
	
	/**
	 * @see IPv4Address#toIPv6()
	 */
	@Override
	public boolean isIPv6Convertible() {
		IPAddressConverter conv = addressConverter;
		return conv != null && conv.isIPv6Convertible(this);
	}
	
	/**
	 * Returns this address converted to IPv6.
	 * 

* This uses {@link #isIPv6Convertible()} to determine convertibility, and that uses an instance of {@link IPAddressConverter.DefaultAddressConverter} which uses IPv4-mapped address mappings from rfc 4038. *

* Override this method and {@link IPv6Address#isIPv4Convertible()} if you wish to map IPv4 to IPv6 according to the mappings defined by * in {@link IPv6Address#isIPv4Compatible()}, {@link IPv6Address#isIPv4Mapped()}, {@link IPv6Address#is6To4()} or some other mapping. *

* If you override this method, you should also override the {@link IPv4Address#isIPv6Convertible()} method to match this behaviour, * and potentially also override the reverse conversion {@link IPv6Address#toIPv4()} in your {@link IPv6Address} subclass. */ @Override public IPv6Address toIPv6() { IPAddressConverter conv = addressConverter; if(conv != null && conv.isIPv6Convertible(this)) { return conv.toIPv6(this); } return null; } private IPv4Address getLowestOrHighest(boolean lowest) { return getSingle(this, () -> { IPv4AddressSection section = getSection(); IPv4AddressSegment[] segs = createSingle(section, getAddressCreator(), i -> { IPv4AddressSegment seg = getSegment(i); return lowest ? seg.getLower() : seg.getUpper(); }); return getAddressCreator().createAddressInternal(segs); /* address creation */ }); } @Override public IPv4Address getLower() { return getLowestOrHighest(true); } @Override public IPv4Address getUpper() { return getLowestOrHighest(false); } @Override public Iterator iterator() { return iterator( this, getAddressCreator(),//using a lambda for this one results in a big performance hit () -> getSection().getLowerSegments(), index -> getSegment(index).iterator()); } @Override public Iterable getAddresses() { return this; } public static IPv4AddressNetwork network() { return network; } private static IPv4AddressCreator getAddressCreator() { return network.getAddressCreator(); } @Override public IPv4AddressNetwork getNetwork() { return network; } public static IPv4Address getLoopback() { return network.getLoopback(); } public static String[] getStandardLoopbackStrings() { return network.getStandardLoopbackStrings(); } @Override public IPv4Address[] subtract(IPAddress other) { IPv4AddressSection thisSection = getSection(); IPv4AddressSection sections[] = thisSection.subtract(other.getSection()); if(sections == null) { return null; } IPv4AddressCreator creator = getAddressCreator(); IPv4Address result[] = new IPv4Address[sections.length]; for(int i = 0; i < result.length; i++) { result[i] = creator.createAddress(sections[i]); /* address creation */ } return result; } @Override public IPv4Address toSubnet(int networkPrefixLength) throws IPAddressTypeException { IPv4AddressSection thisSection = getSection(); IPv4AddressSection subnetSection = thisSection.toSubnet(networkPrefixLength); if(thisSection == subnetSection) { return this; } return getAddressCreator().createAddress(subnetSection); /* address creation */ } /** * Creates a subnet address using the given mask. */ @Override public IPv4Address toSubnet(IPAddress mask) throws IPAddressTypeException { return toSubnet(mask, null); } /** * Creates a subnet address using the given mask. If networkPrefixLength is non-null, applies the prefix length as well. */ @Override public IPv4Address toSubnet(IPAddress mask, Integer networkPrefixLength) throws IPAddressTypeException { IPv4AddressSection thisSection = getSection(); IPv4AddressSection subnetSection = thisSection.toSubnet(mask.getSection(), networkPrefixLength); if(thisSection == subnetSection) { return this; } return getAddressCreator().createAddress(subnetSection); /* address creation */ } @Override public IPv4AddressSection getNetworkSection(int networkPrefixLength, boolean withPrefixLength) { return getSection().getNetworkSection(networkPrefixLength, withPrefixLength); } @Override public IPv4AddressSection getNetworkSection() { if(isPrefixed()) { return getNetworkSection(getNetworkPrefixLength(), true); } return getNetworkSection(getBitCount(), true); } @Override public IPv4AddressSection getHostSection(int networkPrefixLength) { return getSection().getHostSection(networkPrefixLength); } @Override public IPv4AddressSection getHostSection() { if(isPrefixed()) { return getHostSection(getNetworkPrefixLength()); } return getHostSection(0); } @Override public Inet4Address toInetAddress() { return (Inet4Address) super.toInetAddress(); } /** * @see java.net.InetAddress#isLinkLocalAddress() */ @Override public boolean isLinkLocal() { return getSegment(0).matches(169) && getSegment(1).matches(254); } /** * @see java.net.InetAddress#isSiteLocalAddress() */ @Override public boolean isSiteLocal() { IPv4AddressSegment seg0 = getSegment(0); IPv4AddressSegment seg1 = getSegment(1); return seg0.matches(10) || seg0.matches(172) && seg1.matchesWithPrefix(16, 4) || seg0.matches(192) && seg1.matches(168); } @Override public boolean isMulticast() { // 1110... return getSegment(0).matchesWithPrefix(0xff, 4); } /** * @see java.net.InetAddress#isLoopbackAddress() */ @Override public boolean isLoopback() { return getSegment(0).matches(127); } /** * Returns a string like the inet_aton style string * @return */ public String toInetAtonString(IPv4Address.inet_aton_radix radix) { return getSection().toInetAtonString(radix); } public String toInetAtonString(IPv4Address.inet_aton_radix radix, int joinedCount) { return getSection().toInetAtonString(radix, joinedCount); } @Override public String toUNCHostName() { return super.toCanonicalString(); } @Override public String toReverseDNSLookupString() { String result; IPv4AddressSection section = getSection(); if(section.hasNoStringCache() || (result = section.stringCache.reverseDNSString) == null) { section.stringCache.reverseDNSString = result = toNormalizedString(IPv4StringCache.reverseDNSParams); } return result; } @Override public IPAddressPartStringCollection toStandardStringCollection() { return toStringCollection(IPv4StringBuilderOptions.STANDARD_OPTS); } @Override public IPAddressPartStringCollection toAllStringCollection() { return toStringCollection(IPv4StringBuilderOptions.ALL_OPTS); } @Override public IPAddressPartStringCollection toStringCollection(IPStringBuilderOptions opts) { return toStringCollection(IPv4StringBuilderOptions.from(opts)); } private IPv6Address getConverted(IPv4StringBuilderOptions opts) { if(opts.includes(IPv4StringBuilderOptions.IPV6_CONVERSIONS)) { IPv6AddressConverter converter = opts.converter; return converter.toIPv6(this); } return null; } public IPAddressPartStringCollection toStringCollection(IPv4StringBuilderOptions opts) { IPv4StringCollection coll = new IPv4StringCollection(); IPAddressPartStringCollection sectionColl = getSection().toStringCollection(opts); coll.addAll(sectionColl); IPv6Address ipv6Addr = getConverted(opts); if(ipv6Addr != null) { IPAddressPartStringCollection ipv6StringCollection = ipv6Addr.toStringCollection(opts.ipv6ConverterOptions); coll.addAll(ipv6StringCollection); } return coll; } /** * @custom.core * @author sfoley * */ public interface IPv4AddressConverter { /** * If the given address is IPv4, or can be converted to IPv4, returns that {@link IPv4Address}. Otherwise, returns null. */ IPv4Address toIPv4(IPAddress address); } /** * @author sfoley * */ public static enum inet_aton_radix { OCTAL, HEX, DECIMAL; int getRadix() { if(this == OCTAL) { return 8; } else if(this == HEX) { return 16; } return 10; } String getSegmentStrPrefix() { if(this == OCTAL) { return "0"; } else if(this == HEX) { return "0x"; } return null; } }; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy