1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * ident	"%Z%%M%	%I%	%E% SMI"
24  *
25  * Copyright 1998-2002 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 package com.sun.dhcpmgr.data;
29 
30 import java.net.InetAddress;
31 import java.util.StringTokenizer;
32 import java.io.Serializable;
33 import java.text.MessageFormat;
34 
35 /**
36  * This class provides a container for holding IP Addresses.  It is different
37  * from java.net.InetAddress in that it allows for constructing an arbitrary IP
38  * address, rather than forcing you to use InetAddress.getByName, which can
39  * generate all sorts of nasty exception conditions in applets, especially when
40  * doing a configuration-type app which handles addresses which are not
41  * necessarily resolvable in any nameservice.
42  */
43 public class IPAddress implements Cloneable, Serializable {
44     private byte [] bytes = new byte[] { 0, 0, 0, 0 };
45 
46     // Serialization id for this class
47     static final long serialVersionUID = -7439646692550395242L;
48 
49     /**
50      * Construct an empty address
51      */
IPAddress()52     public IPAddress() {
53     }
54 
55     /**
56      * Construct an address for the dotted-decimal <code>String</code> supplied.
57      *
58      */
IPAddress(String s)59     public IPAddress(String s) throws ValidationException {
60 	try {
61 	    // If the input looks like a valid format, try parsing it
62 	    char [] chars = s.toCharArray();
63 	    int dots = 0; // Count number of periods
64 	    for (int i = 0; i < chars.length; ++i) {
65 		if (Character.isDigit(chars[i])) {
66 		    continue;
67 		}
68 		if ((chars[i] == '.')) {
69 		    if (++dots > 3) {
70 			// Too many; we're done
71 			throwException(s);
72 		    }
73 		    continue;
74 		}
75 		/*
76 		 * Can't be an address, so let InetAdddress try to resolve it
77 		 * as a name
78 		 */
79 		InetAddress a = InetAddress.getByName(s);
80 		bytes = a.getAddress();
81 		return;
82 	    }
83 	    // Looks like an IP address; parse it
84 	    StringTokenizer st = new StringTokenizer(s, ".");
85 	    int b = 0;
86 	    while (st.hasMoreTokens()) {
87 		/*
88 		 * Byte won't parse anything larger than 127 since it thinks
89 		 * everything's signed, so use Short instead
90 		 */
91 		short shortVal = Short.parseShort(st.nextToken());
92 		if (shortVal > 255 || shortVal < 0) {
93 		    throwException(s);
94 		}
95 		bytes[b++] = (byte)shortVal;
96 	    }
97 	    if (b < 4) {
98 		// Not a fully specified address; don't read caller's mind
99 		throwException(s);
100 	    }
101 	} catch (ValidationException e) {
102 	    // Just re-throw it
103 	    throw e;
104 	} catch (Throwable e) {
105 	    // Convert other exceptions to ValidationException
106 	    throw new ValidationException(e.getMessage());
107 	}
108     }
109 
110     /**
111      * Construct an IPAddress from an InetAddress
112      * @param a The InetAddress to convert
113      */
IPAddress(InetAddress a)114     public IPAddress(InetAddress a) {
115 	bytes = a.getAddress();
116     }
117 
118     /**
119      * Construct an IP address from an arbitrary 32-bit value
120      * @param addr The value to use
121      */
IPAddress(int addr)122     public IPAddress(int addr) {
123 	bytes = new byte[4];
124 	for (int i = 0; i < 4; ++i) {
125 	    // Careful; must mask to fight sign-extension
126 	    bytes[i] = (byte)((addr >> (8 * (3 - i))) & 0xff);
127 	}
128     }
129 
toString()130     public String toString() {
131 	StringBuffer b = new StringBuffer();
132 	for (int i = 0; i < 4; ++i) {
133 	    if (i != 0) {
134 		b.append('.');
135 	    }
136 	    // Careful; must mask to fight sign-extension
137 	    b.append((int)bytes[i] & 0xff);
138 	}
139 	return b.toString();
140     }
141 
142     /**
143      * Convert this address to an <code>int</code>
144      * @return The address as an <code>int</code>
145      */
intValue()146     public int intValue() {
147 	int i = 0;
148 	for (int j = 0; j < 4; ++j) {
149 	    // Careful; must mask to fight sign-extension
150 	    i |= ((int)bytes[j] & 0xff) << (8 * (3 - j));
151 	}
152 	return i;
153     }
154 
155     /**
156      * Try to convert to a name
157      * @return The hostname for this address, if one can be found.  Otherwise,
158      *		dotted-decimal form of this address is returned.
159      */
getHostName()160     public String getHostName() {
161 	try {
162 	    return InetAddress.getByName(toString()).getHostName();
163 	} catch (Throwable e) {
164 	    return toString();
165 	}
166     }
167 
168     /**
169      * Provide the individual bytes of the address a la InetAddress
170      * @return A byte array of the address
171      */
getAddress()172     public byte [] getAddress() {
173 	return bytes;
174     }
175 
176     /**
177      * @return the dotted-decimal string representing this address
178      */
getHostAddress()179     public String getHostAddress() {
180 	return toString();
181     }
182 
183     /**
184      * Compare this IP address to either another IP address or a
185      * <code>java.net.InetAddress</code>.
186      * @return <code>true</code> if the addresses are the same.
187      */
equals(Object obj)188     public boolean equals(Object obj) {
189 	if (obj == null) {
190 	    return false;
191 	}
192 
193 	byte [] ba;
194 
195 	if (obj instanceof InetAddress) {
196 	    ba = ((InetAddress)obj).getAddress();
197 	} else if (obj instanceof IPAddress) {
198 	    ba = ((IPAddress)obj).getAddress();
199 	} else {
200 	    return false;
201 	}
202 
203 	if (ba.length != bytes.length) {
204 	    return false;
205 	}
206 
207 	for (int i = 0; i < bytes.length; ++i) {
208 	    if (ba[i] != bytes[i]) {
209 		return false;
210 	    }
211 	}
212 
213 	return true;
214     }
215 
216     /**
217      * Make a copy of this address
218      * @return a new IPAddress
219      */
clone()220     public Object clone() {
221 	IPAddress a = new IPAddress();
222 	a.bytes = (byte [])bytes.clone();
223 	return a;
224     }
225 
226     /**
227      * Retrieve the IP address as a number suitable for arithmetic operations.
228      * We use a <code>long</code> rather than an <code>int</code> in order to
229      * be able to treat it as an unsigned value, since all Java types are
230      * signed.
231      * @return The IP address as a <code>long</code>.
232      */
getBinaryAddress()233     public long getBinaryAddress() {
234 	byte [] bytes = getAddress();
235 	long result = 0;
236 	for (int i = 0; i < bytes.length; ++i) {
237 	    // Defeat sign extension with cast & mask
238 	    result |= ((long)bytes[i] & 0xff) << (24-(i*8));
239 	}
240 	return result;
241     }
242 
throwException(String s)243     private void throwException(String s)
244 	throws ValidationException {
245 	Object [] args = { s };
246 	MessageFormat form = new MessageFormat(
247 	    ResourceStrings.getString("invalid_ip_address"));
248 	String msg = form.format(args);
249 	throw new ValidationException(msg);
250     }
251 }
252