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; 020 021import org.apache.reef.wake.exception.WakeRuntimeException; 022 023import java.net.Inet4Address; 024import java.net.InetAddress; 025import java.net.NetworkInterface; 026import java.net.SocketException; 027import java.util.Comparator; 028import java.util.Enumeration; 029import java.util.TreeSet; 030import java.util.concurrent.atomic.AtomicReference; 031import java.util.logging.Level; 032import java.util.logging.Logger; 033 034public class NetUtils { 035 private static final Logger LOG = Logger.getLogger(NetUtils.class.getName()); 036 037 private static AtomicReference<String> cached = new AtomicReference<>(); 038 039 public static String getLocalAddress() { 040 // This method is surprisingly slow: It was causing unit test timeouts, so we memoize the result. 041 if (cached.get() == null) { 042 Enumeration<NetworkInterface> ifaces; 043 try { 044 ifaces = NetworkInterface.getNetworkInterfaces(); 045 TreeSet<Inet4Address> sortedAddrs = new TreeSet<>(new AddressComparator()); 046 // There is an idea of virtual / subinterfaces exposed by java here. 047 // We're not walking around looking for those because the javadoc says: 048 049 // "NOTE: can use getNetworkInterfaces()+getInetAddresses() to obtain all IP addresses for this node" 050 051 while (ifaces.hasMoreElements()) { 052 NetworkInterface iface = ifaces.nextElement(); 053// if(iface.isUp()) { // leads to slowness and non-deterministic return values, so don't call isUp(). 054 Enumeration<InetAddress> addrs = iface.getInetAddresses(); 055 while (addrs.hasMoreElements()) { 056 InetAddress a = addrs.nextElement(); 057 if (a instanceof Inet4Address) { 058 sortedAddrs.add((Inet4Address) a); 059 } 060// } 061 } 062 } 063 if (sortedAddrs.isEmpty()) { 064 throw new WakeRuntimeException("This machine apparently doesn't have any IP addresses (not even 127.0.0.1) on interfaces that are up."); 065 } 066 cached.set(sortedAddrs.pollFirst().getHostAddress()); 067 LOG.log(Level.FINE, "Local address is {0}", cached.get()); 068 } catch (SocketException e) { 069 throw new WakeRuntimeException("Unable to get local host address", 070 e.getCause()); 071 } 072 } 073 return cached.get(); 074 } 075 076 private static class AddressComparator implements Comparator<Inet4Address> { 077 078 // get unsigned byte. 079 private static int u(byte b) { 080 return ((int) b);// & 0xff; 081 } 082 083 @Override 084 public int compare(Inet4Address aa, Inet4Address ba) { 085 byte[] a = aa.getAddress(); 086 byte[] b = ba.getAddress(); 087 // local subnet comes after all else. 088 if (a[0] == 127 && b[0] != 127) { 089 return 1; 090 } 091 if (a[0] != 127 && b[0] == 127) { 092 return -1; 093 } 094 for (int i = 0; i < 4; i++) { 095 if (u(a[i]) < u(b[i])) { 096 return -1; 097 } 098 if (u(a[i]) > u(b[i])) { 099 return 1; 100 } 101 } 102 return 0; 103 } 104 } 105 106}