660 * @return a string representation of this IP address.
661 */
662 public String toString() {
663 return ((hostName != null) ? hostName : "")
664 + "/" + getHostAddress();
665 }
666
667 /*
668 * Cached addresses - our own litle nis, not!
669 */
670 private static Cache addressCache = new Cache(Cache.Type.Positive);
671
672 private static Cache negativeCache = new Cache(Cache.Type.Negative);
673
674 private static boolean addressCacheInit = false;
675
676 static InetAddress[] unknown_array; // put THIS in cache
677
678 static InetAddressImpl impl;
679
680 private static HashMap<String, InetAddress[]> lookupTable
681 = new HashMap<String, InetAddress[]>();
682
683 /**
684 * Represents a cache entry
685 */
686 static final class CacheEntry {
687
688 CacheEntry(InetAddress[] addresses, long expiration) {
689 this.addresses = addresses;
690 this.expiration = expiration;
691 }
692
693 InetAddress[] addresses;
694 long expiration;
695 }
696
697 /**
698 * A cache that manages entries based on a policy specified
699 * at creation time.
700 */
701 static final class Cache {
720 }
721 }
722
723 /**
724 * Add an entry to the cache. If there's already an
725 * entry then for this host then the entry will be
726 * replaced.
727 */
728 public Cache put(String host, InetAddress[] addresses) {
729 int policy = getPolicy();
730 if (policy == InetAddressCachePolicy.NEVER) {
731 return this;
732 }
733
734 // purge any expired entries
735
736 if (policy != InetAddressCachePolicy.FOREVER) {
737
738 // As we iterate in insertion order we can
739 // terminate when a non-expired entry is found.
740 LinkedList<String> expired = new LinkedList<String>();
741 long now = System.currentTimeMillis();
742 for (String key : cache.keySet()) {
743 CacheEntry entry = cache.get(key);
744
745 if (entry.expiration >= 0 && entry.expiration < now) {
746 expired.add(key);
747 } else {
748 break;
749 }
750 }
751
752 for (String key : expired) {
753 cache.remove(key);
754 }
755 }
756
757 // create new entry and add it to the cache
758 // -- as a HashMap replaces existing entries we
759 // don't need to explicitly check if there is
760 // already an entry for this host.
1210
1211 // Check whether the host is in the lookupTable.
1212 // 1) If the host isn't in the lookupTable when
1213 // checkLookupTable() is called, checkLookupTable()
1214 // would add the host in the lookupTable and
1215 // return null. So we will do the lookup.
1216 // 2) If the host is in the lookupTable when
1217 // checkLookupTable() is called, the current thread
1218 // would be blocked until the host is removed
1219 // from the lookupTable. Then this thread
1220 // should try to look up the addressCache.
1221 // i) if it found the addresses in the
1222 // addressCache, checkLookupTable() would
1223 // return the addresses.
1224 // ii) if it didn't find the addresses in the
1225 // addressCache for any reason,
1226 // it should add the host in the
1227 // lookupTable and return null so the
1228 // following code would do a lookup itself.
1229 if ((addresses = checkLookupTable(host)) == null) {
1230 // This is the first thread which looks up the addresses
1231 // this host or the cache entry for this host has been
1232 // expired so this thread should do the lookup.
1233 for (NameService nameService : nameServices) {
1234 try {
1235 /*
1236 * Do not put the call to lookup() inside the
1237 * constructor. if you do you will still be
1238 * allocating space when the lookup fails.
1239 */
1240
1241 addresses = nameService.lookupAllHostAddr(host);
1242 success = true;
1243 break;
1244 } catch (UnknownHostException uhe) {
1245 if (host.equalsIgnoreCase("localhost")) {
1246 InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
1247 addresses = local;
1248 success = true;
1249 break;
1250 }
1251 else {
1252 addresses = unknown_array;
1253 success = false;
1254 ex = uhe;
1255 }
1256 }
1257 }
1258
1259 // Cache the addresses.
1260 cacheAddresses(host, addresses, success);
1261 // Delete the host from the lookupTable, and
1262 // notify all threads waiting for the monitor
1263 // for lookupTable.
1264 updateLookupTable(host);
1265 if (!success && ex != null)
1266 throw ex;
1267 }
1268
1269 return addresses;
1270 }
1271
1272
1273 private static InetAddress[] checkLookupTable(String host) {
1274 // make sure addresses is null.
1275 InetAddress[] addresses = null;
1276
1277 synchronized (lookupTable) {
1278 // If the host isn't in the lookupTable, add it in the
1279 // lookuptable and return null. The caller should do
1280 // the lookup.
1281 if (lookupTable.containsKey(host) == false) {
1282 lookupTable.put(host, null);
1283 return addresses;
1284 }
1285
1286 // If the host is in the lookupTable, it means that another
1287 // thread is trying to look up the addresses of this host.
1288 // This thread should wait.
1289 while (lookupTable.containsKey(host)) {
1290 try {
1291 lookupTable.wait();
1292 } catch (InterruptedException e) {
1293 }
1294 }
1295 }
1296
1297 // The other thread has finished looking up the addresses of
1298 // the host. This thread should retry to get the addresses
1299 // from the addressCache. If it doesn't get the addresses from
1300 // the cache, it will try to look up the addresses itself.
1301 addresses = getCachedAddresses(host);
1302 if (addresses == null) {
1303 synchronized (lookupTable) {
1304 lookupTable.put(host, null);
1305 }
1306 }
1307
1308 return addresses;
1309 }
1310
1311 private static void updateLookupTable(String host) {
1312 synchronized (lookupTable) {
1313 lookupTable.remove(host);
1314 lookupTable.notifyAll();
1315 }
1316 }
1317
1318 /**
1319 * Returns an <code>InetAddress</code> object given the raw IP address .
1320 * The argument is in network byte order: the highest order
1321 * byte of the address is in <code>getAddress()[0]</code>.
1322 *
1323 * <p> This method doesn't block, i.e. no reverse name service lookup
1324 * is performed.
|
660 * @return a string representation of this IP address.
661 */
662 public String toString() {
663 return ((hostName != null) ? hostName : "")
664 + "/" + getHostAddress();
665 }
666
667 /*
668 * Cached addresses - our own litle nis, not!
669 */
670 private static Cache addressCache = new Cache(Cache.Type.Positive);
671
672 private static Cache negativeCache = new Cache(Cache.Type.Negative);
673
674 private static boolean addressCacheInit = false;
675
676 static InetAddress[] unknown_array; // put THIS in cache
677
678 static InetAddressImpl impl;
679
680 private static final HashMap<String, Void> lookupTable = new HashMap<>();
681
682 /**
683 * Represents a cache entry
684 */
685 static final class CacheEntry {
686
687 CacheEntry(InetAddress[] addresses, long expiration) {
688 this.addresses = addresses;
689 this.expiration = expiration;
690 }
691
692 InetAddress[] addresses;
693 long expiration;
694 }
695
696 /**
697 * A cache that manages entries based on a policy specified
698 * at creation time.
699 */
700 static final class Cache {
719 }
720 }
721
722 /**
723 * Add an entry to the cache. If there's already an
724 * entry then for this host then the entry will be
725 * replaced.
726 */
727 public Cache put(String host, InetAddress[] addresses) {
728 int policy = getPolicy();
729 if (policy == InetAddressCachePolicy.NEVER) {
730 return this;
731 }
732
733 // purge any expired entries
734
735 if (policy != InetAddressCachePolicy.FOREVER) {
736
737 // As we iterate in insertion order we can
738 // terminate when a non-expired entry is found.
739 LinkedList<String> expired = new LinkedList<>();
740 long now = System.currentTimeMillis();
741 for (String key : cache.keySet()) {
742 CacheEntry entry = cache.get(key);
743
744 if (entry.expiration >= 0 && entry.expiration < now) {
745 expired.add(key);
746 } else {
747 break;
748 }
749 }
750
751 for (String key : expired) {
752 cache.remove(key);
753 }
754 }
755
756 // create new entry and add it to the cache
757 // -- as a HashMap replaces existing entries we
758 // don't need to explicitly check if there is
759 // already an entry for this host.
1209
1210 // Check whether the host is in the lookupTable.
1211 // 1) If the host isn't in the lookupTable when
1212 // checkLookupTable() is called, checkLookupTable()
1213 // would add the host in the lookupTable and
1214 // return null. So we will do the lookup.
1215 // 2) If the host is in the lookupTable when
1216 // checkLookupTable() is called, the current thread
1217 // would be blocked until the host is removed
1218 // from the lookupTable. Then this thread
1219 // should try to look up the addressCache.
1220 // i) if it found the addresses in the
1221 // addressCache, checkLookupTable() would
1222 // return the addresses.
1223 // ii) if it didn't find the addresses in the
1224 // addressCache for any reason,
1225 // it should add the host in the
1226 // lookupTable and return null so the
1227 // following code would do a lookup itself.
1228 if ((addresses = checkLookupTable(host)) == null) {
1229 try {
1230 // This is the first thread which looks up the addresses
1231 // this host or the cache entry for this host has been
1232 // expired so this thread should do the lookup.
1233 for (NameService nameService : nameServices) {
1234 try {
1235 /*
1236 * Do not put the call to lookup() inside the
1237 * constructor. if you do you will still be
1238 * allocating space when the lookup fails.
1239 */
1240
1241 addresses = nameService.lookupAllHostAddr(host);
1242 success = true;
1243 break;
1244 } catch (UnknownHostException uhe) {
1245 if (host.equalsIgnoreCase("localhost")) {
1246 InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
1247 addresses = local;
1248 success = true;
1249 break;
1250 }
1251 else {
1252 addresses = unknown_array;
1253 success = false;
1254 ex = uhe;
1255 }
1256 }
1257 }
1258
1259 // Cache the addresses.
1260 cacheAddresses(host, addresses, success);
1261 if (!success && ex != null)
1262 throw ex;
1263 } finally {
1264 // Delete host from the lookupTable and notify
1265 // all threads waiting on the lookupTable monitor.
1266 updateLookupTable(host);
1267 }
1268 }
1269
1270 return addresses;
1271 }
1272
1273
1274 private static InetAddress[] checkLookupTable(String host) {
1275 synchronized (lookupTable) {
1276 // If the host isn't in the lookupTable, add it in the
1277 // lookuptable and return null. The caller should do
1278 // the lookup.
1279 if (lookupTable.containsKey(host) == false) {
1280 lookupTable.put(host, null);
1281 return null;
1282 }
1283
1284 // If the host is in the lookupTable, it means that another
1285 // thread is trying to look up the addresses of this host.
1286 // This thread should wait.
1287 while (lookupTable.containsKey(host)) {
1288 try {
1289 lookupTable.wait();
1290 } catch (InterruptedException e) {
1291 }
1292 }
1293 }
1294
1295 // The other thread has finished looking up the addresses of
1296 // the host. This thread should retry to get the addresses
1297 // from the addressCache. If it doesn't get the addresses from
1298 // the cache, it will try to look up the addresses itself.
1299 InetAddress[] addresses = getCachedAddresses(host);
1300 if (addresses == null) {
1301 synchronized (lookupTable) {
1302 lookupTable.put(host, null);
1303 return null;
1304 }
1305 }
1306
1307 return addresses;
1308 }
1309
1310 private static void updateLookupTable(String host) {
1311 synchronized (lookupTable) {
1312 lookupTable.remove(host);
1313 lookupTable.notifyAll();
1314 }
1315 }
1316
1317 /**
1318 * Returns an <code>InetAddress</code> object given the raw IP address .
1319 * The argument is in network byte order: the highest order
1320 * byte of the address is in <code>getAddress()[0]</code>.
1321 *
1322 * <p> This method doesn't block, i.e. no reverse name service lookup
1323 * is performed.
|