001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.wake.remote.address; 020 021import org.apache.reef.tang.Configuration; 022import org.apache.reef.tang.Tang; 023import org.apache.reef.wake.exception.WakeRuntimeException; 024 025import javax.inject.Inject; 026import java.net.Inet4Address; 027import java.net.InetAddress; 028import java.net.NetworkInterface; 029import java.net.SocketException; 030import java.util.Comparator; 031import java.util.Enumeration; 032import java.util.TreeSet; 033import java.util.concurrent.atomic.AtomicReference; 034import java.util.logging.Level; 035import java.util.logging.Logger; 036 037/** 038 * An implementation of LocalAddressProvider using the (removed) code from NetUtils.getLocalAddress() 039 */ 040public final class LegacyLocalAddressProvider implements LocalAddressProvider { 041 private static final Logger LOG = Logger.getLogger(LegacyLocalAddressProvider.class.getName()); 042 private final AtomicReference<String> cached = new AtomicReference<>(); 043 044 /** 045 * Injectable constructor for Tang only. 046 */ 047 @Inject 048 private LegacyLocalAddressProvider() { 049 LOG.log(Level.INFO, "Instantiating LegacyLocalAddressProvider"); 050 } 051 052 @Override 053 public String getLocalAddress() { 054 // This method is surprisingly slow: It was causing unit test timeouts, so we memoize the result. 055 if (cached.get() == null) { 056 Enumeration<NetworkInterface> ifaces; 057 try { 058 ifaces = NetworkInterface.getNetworkInterfaces(); 059 TreeSet<Inet4Address> sortedAddrs = new TreeSet<>(new AddressComparator()); 060 // There is an idea of virtual / subinterfaces exposed by java here. 061 // We're not walking around looking for those because the javadoc says: 062 063 // "NOTE: can use getNetworkInterfaces()+getInetAddresses() to obtain all IP addresses for this node" 064 065 while (ifaces.hasMoreElements()) { 066 NetworkInterface iface = ifaces.nextElement(); 067// if(iface.isUp()) { // leads to slowness and non-deterministic return values, so don't call isUp(). 068 Enumeration<InetAddress> addrs = iface.getInetAddresses(); 069 while (addrs.hasMoreElements()) { 070 InetAddress a = addrs.nextElement(); 071 if (a instanceof Inet4Address) { 072 sortedAddrs.add((Inet4Address) a); 073 } 074// } 075 } 076 } 077 if (sortedAddrs.isEmpty()) { 078 throw new WakeRuntimeException("This machine apparently doesn't have any IP addresses (not even 127.0.0.1) on interfaces that are up."); 079 } 080 cached.set(sortedAddrs.pollFirst().getHostAddress()); 081 LOG.log(Level.FINE, "Local address is {0}", cached.get()); 082 } catch (SocketException e) { 083 throw new WakeRuntimeException("Unable to get local host address", 084 e.getCause()); 085 } 086 } 087 return cached.get(); 088 } 089 090 @Override 091 public Configuration getConfiguration() { 092 return Tang.Factory.getTang().newConfigurationBuilder() 093 .bind(LocalAddressProvider.class, LegacyLocalAddressProvider.class) 094 .build(); 095 } 096 097 private static class AddressComparator implements Comparator<Inet4Address> { 098 099 // get unsigned byte. 100 private static int u(byte b) { 101 return ((int) b);// & 0xff; 102 } 103 104 @Override 105 public int compare(Inet4Address aa, Inet4Address ba) { 106 byte[] a = aa.getAddress(); 107 byte[] b = ba.getAddress(); 108 // local subnet comes after all else. 109 if (a[0] == 127 && b[0] != 127) { 110 return 1; 111 } 112 if (a[0] != 127 && b[0] == 127) { 113 return -1; 114 } 115 for (int i = 0; i < 4; i++) { 116 if (u(a[i]) < u(b[i])) { 117 return -1; 118 } 119 if (u(a[i]) > u(b[i])) { 120 return 1; 121 } 122 } 123 return 0; 124 } 125 } 126}