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 final Enumeration<NetworkInterface> ifaces; 057 try { 058 ifaces = NetworkInterface.getNetworkInterfaces(); 059 final 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 final NetworkInterface iface = ifaces.nextElement(); 067// if(iface.isUp()) { // leads to slowness and non-deterministic return values, so don't call isUp(). 068 final Enumeration<InetAddress> addrs = iface.getInetAddresses(); 069 while (addrs.hasMoreElements()) { 070 final 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) " + 079 "on interfaces that are up."); 080 } 081 cached.set(sortedAddrs.pollFirst().getHostAddress()); 082 LOG.log(Level.FINE, "Local address is {0}", cached.get()); 083 } catch (final SocketException e) { 084 throw new WakeRuntimeException("Unable to get local host address", 085 e.getCause()); 086 } 087 } 088 return cached.get(); 089 } 090 091 @Override 092 public Configuration getConfiguration() { 093 return Tang.Factory.getTang().newConfigurationBuilder() 094 .bind(LocalAddressProvider.class, LegacyLocalAddressProvider.class) 095 .build(); 096 } 097 098 private static class AddressComparator implements Comparator<Inet4Address> { 099 100 // get unsigned byte. 101 private static int u(final byte b) { 102 return ((int) b); // & 0xff; 103 } 104 105 @Override 106 public int compare(final Inet4Address aa, final Inet4Address ba) { 107 final byte[] a = aa.getAddress(); 108 final byte[] b = ba.getAddress(); 109 // local subnet comes after all else. 110 if (a[0] == 127 && b[0] != 127) { 111 return 1; 112 } 113 if (a[0] != 127 && b[0] == 127) { 114 return -1; 115 } 116 for (int i = 0; i < 4; i++) { 117 if (u(a[i]) < u(b[i])) { 118 return -1; 119 } 120 if (u(a[i]) > u(b[i])) { 121 return 1; 122 } 123 } 124 return 0; 125 } 126 } 127}