c0db407d7ff8be37454bf16b597465628c5fba81
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / Subnet.java
1 package org.opendaylight.controller.packetcable.provider;
2 import java.math.BigInteger;
3 import java.net.InetAddress;
4 import java.net.UnknownHostException;
5
6 /**
7  * @author c3oe.de, based on snippets from Scott Plante, John Kugelmann
8  */
9 public class Subnet
10 {
11     final private int bytesSubnetCount;
12     final private BigInteger bigMask;
13     final private BigInteger bigSubnetMasked;
14     final private int prefixLen;
15
16     /** For use via format "192.168.0.0/24" or "2001:db8:85a3:880:0:0:0:0/57" */
17     public Subnet( final InetAddress subnetAddress, final int bits )
18     {
19         this.prefixLen = bits;
20         this.bytesSubnetCount = subnetAddress.getAddress().length; // 4 or 16
21         this.bigMask = BigInteger.valueOf( -1 ).shiftLeft( this.bytesSubnetCount*8 - bits ); // mask = -1 << 32 - bits
22         this.bigSubnetMasked = new BigInteger( subnetAddress.getAddress() ).and( this.bigMask );
23     }
24
25     /** For use via format "192.168.0.0/255.255.255.0" or single address */
26     public Subnet( final InetAddress subnetAddress, final InetAddress mask )
27     {
28         this.bytesSubnetCount = subnetAddress.getAddress().length;
29         this.bigMask = null == mask ? BigInteger.valueOf( -1 ) : new BigInteger( mask.getAddress() ); // no mask given case is handled here.
30         this.bigSubnetMasked = new BigInteger( subnetAddress.getAddress() ).and( this.bigMask );
31         int lowestSetBit = bigMask.getLowestSetBit();
32         this.prefixLen = lowestSetBit == -1 ? 0 : 32 - lowestSetBit;
33     }
34
35     /**
36      * Subnet factory method.
37      * @param subnetMask format: "192.168.0.0/24" or "192.168.0.0/255.255.255.0"
38      *      or single address or "2001:db8:85a3:880:0:0:0:0/57"
39      * @return a new instance
40      * @throws UnknownHostException thrown if unsupported subnet mask.
41      */
42     public static Subnet createInstance( final String subnetMask )
43             throws UnknownHostException
44     {
45         final String[] stringArr = subnetMask.split("/");
46         if ( 2 > stringArr.length )
47             return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), null);
48         else if ( stringArr[ 1 ].contains(".") || stringArr[ 1 ].contains(":") )
49             return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), InetAddress.getByName( stringArr[ 1 ] ) );
50         else
51             return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), Integer.parseInt( stringArr[ 1 ] ) );
52     }
53
54     public int getPrefixLen() {
55                 return prefixLen;
56         }
57
58         public boolean isInNet( final InetAddress address )
59     {
60         final byte[] bytesAddress = address.getAddress();
61         if ( this.bytesSubnetCount != bytesAddress.length )
62             return false;
63         final BigInteger bigAddress = new BigInteger( bytesAddress );
64         return  bigAddress.and( this.bigMask ).equals( this.bigSubnetMasked );
65     }
66
67     @Override
68     final public boolean equals( Object obj )
69     {
70         if ( ! (obj instanceof Subnet) )
71             return false;
72         final Subnet other = (Subnet)obj;
73         return  this.bigSubnetMasked.equals( other.bigSubnetMasked ) &&
74                 this.bigMask.equals( other.bigMask ) &&
75                 this.bytesSubnetCount == other.bytesSubnetCount;
76     }
77
78     @Override
79     final public int hashCode()
80     {
81         return this.bytesSubnetCount;
82     }
83
84     @Override
85     public String toString()
86     {
87         final StringBuilder buf = new StringBuilder();
88         bigInteger2IpString( buf, this.bigSubnetMasked, this.bytesSubnetCount );
89         buf.append( '/' );
90         bigInteger2IpString( buf, this.bigMask, this.bytesSubnetCount );
91         return buf.toString();
92     }
93
94     static private void bigInteger2IpString( final StringBuilder buf, final BigInteger bigInteger, final int displayBytes )
95     {
96         final boolean isIPv4 = 4 == displayBytes;
97         byte[] bytes = bigInteger.toByteArray();
98         int diffLen = displayBytes - bytes.length;
99         final byte fillByte = 0 > (int)bytes[ 0 ] ? (byte)0xFF : (byte)0x00;
100
101         int integer;
102         for ( int i = 0; i < displayBytes; i++ )
103         {
104             if ( 0 < i && ! isIPv4 && i % 2 == 0 )
105                 buf.append( ':' );
106             else if ( 0 < i && isIPv4 )
107                 buf.append( '.' );
108             integer = 0xFF & (i < diffLen ? fillByte : bytes[ i - diffLen ]);
109             if ( ! isIPv4 && 0x10 > integer )
110                 buf.append( '0' );
111             buf.append( isIPv4 ? integer : Integer.toHexString( integer ) );
112         }
113     }
114 }