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 */ 52 public IPAddress() { 53 } 54 55 /** 56 * Construct an address for the dotted-decimal <code>String</code> supplied. 57 * 58 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 172 public byte [] getAddress() { 173 return bytes; 174 } 175 176 /** 177 * @return the dotted-decimal string representing this address 178 */ 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 */ 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 */ 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 */ 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 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 }