001package net.gdface.thrift;
002import java.net.InetAddress;
003import java.net.NetworkInterface;
004import java.net.SocketException;
005import java.net.UnknownHostException;
006import java.util.Iterator;
007import java.util.List;
008import java.util.Set;
009
010import static com.google.common.base.Preconditions.checkNotNull;
011
012import com.google.common.collect.ImmutableSet;
013import com.google.common.collect.Iterators;
014
015import com.google.common.base.Predicates;
016
017import com.google.common.base.Joiner;
018
019import com.google.common.base.Predicate;
020import com.google.common.collect.Lists;
021import com.google.common.primitives.Bytes;
022
023import com.google.common.base.Function;
024
025/**
026 * 网络管理工具类
027 * @author guyadong
028 * @deprecated instead use {@link net.gdface.utils.NetworkUtil} in com.gitee.l0km:common-base2 since version 1.0.7
029 */
030public class NetworkUtil {
031    public static final String DEFAULT_HOST = "localhost";
032    public static enum Radix{
033        /** 二进制 */BIN(2),
034        /** 十进制 */DEC(10),
035        /** 十六进制 */HEX(16);
036        final int value;
037        Radix(int radix){
038            this.value = radix;
039        }
040    }
041    public static enum Filter implements Predicate<NetworkInterface>{
042        /** 过滤器: 所有网卡 */ALL,
043        /** 过滤器: 在线设备,see also {@link NetworkInterface#isUp()} */UP,
044        /** 过滤器: 虚拟接口,see also {@link NetworkInterface#isVirtual()} */VIRTUAL,
045        /** 过滤器:LOOPBACK, see also {@link NetworkInterface#isLoopback()} */LOOPBACK,
046        /** 过滤器:物理网卡 */PHYICAL_ONLY;
047
048        @Override
049        public boolean apply(NetworkInterface input) {
050            if(null == input ){
051                return false;
052            }
053            try{
054                switch(this){
055                case UP:
056                    return input.isUp();
057                case VIRTUAL:
058                    return input.isVirtual();
059                case LOOPBACK:
060                    return input.isLoopback();
061                case PHYICAL_ONLY :{
062                    byte[] hardwareAddress = input.getHardwareAddress();
063                    return null != hardwareAddress 
064                            && hardwareAddress.length > 0 
065                            && !input.isVirtual() 
066                            && !isVMMac(hardwareAddress);
067                }
068                case ALL:
069                default :
070                    return true;
071                }
072            } catch (SocketException e) {
073                throw new RuntimeException(e);
074            }
075        }
076    }
077    /**
078     * 根据过滤器{@code filters}指定的条件(AND)返回网卡设备对象
079     * @param filters
080     * @return
081     */
082    @SafeVarargs
083    @SuppressWarnings("unchecked")
084    public static Set<NetworkInterface> getNICs(Predicate<NetworkInterface> ...filters) {
085        if(null == filters){
086            filters = new Predicate[]{Filter.ALL};
087        }
088        try {
089            Iterator<NetworkInterface> filtered = Iterators.filter(
090                    Iterators.forEnumeration(NetworkInterface.getNetworkInterfaces()),
091                    Predicates.and(filters));
092            return ImmutableSet.copyOf(filtered);
093        } catch (SocketException e) {
094            throw new RuntimeException(e);
095        } 
096    }
097    /**
098     * 返回所有物理网卡
099     * @return
100     */
101    public static Set<NetworkInterface> getPhysicalNICs() {
102        return getNICs(Filter.PHYICAL_ONLY,Filter.UP);
103    }
104    /**
105     * 将{@code byte[]} 转换为{@code radix}指定格式的字符串
106     * 
107     * @param source 
108     * @param separator 分隔符
109     * @param radix 进制基数
110     * @return {@code source}为{@code null}时返回空字符串
111     */
112    public static final String format(byte[] source,String separator, final Radix radix) {
113        if (null == source){
114            return "";
115        }
116        if(null == separator){
117            separator = "";
118        }
119        List<String> hex = Lists.transform(Bytes.asList(source),new Function<Byte,String>(){
120            @Override
121            public String apply(Byte input) {
122                return String.copyValueOf(new char[]{
123                        Character.forDigit((input & 240) >> 4, radix.value),
124                        Character.forDigit(input & 15, radix.value)
125                });
126            }});
127        return Joiner.on(separator).join(hex);
128    }
129    /** 
130     * MAC地址格式(16进制)格式化{@code source}指定的字节数组 
131     * @see #format(byte[], String, Radix)
132     */
133    public static final String formatMac(byte[] source,String separator) {
134        return format(source,separator,Radix.HEX);
135    }
136    /** 
137     * 以IP地址格式(点分位)格式化{@code source}指定的字节数组<br>
138     * @see #format(byte[], String, Radix) 
139     */
140    public static final String formatIp(byte[] source) {
141        return format(source,".",Radix.DEC);
142    }
143    /**
144     * 返回指定{@code address}绑定的网卡的物理地址(MAC)
145     * @param address
146     * @return 指定的{@code address}没有绑定在任何网卡上返回{@code null}
147     * @see NetworkInterface#getByInetAddress(InetAddress)
148     * @see NetworkInterface#getHardwareAddress()
149     */
150    public static byte[] getMacAddress(InetAddress address) {
151        try {
152            NetworkInterface nic = NetworkInterface.getByInetAddress(address);
153            return null == nic ? null  : nic.getHardwareAddress();
154        } catch (SocketException e) {
155            throw new RuntimeException(e);
156        }
157    }
158    /**
159     * @param nic 网卡对象
160     * @param separator 格式化分隔符
161     * @return 表示MAC地址的字符串
162     */
163    public static String getMacAddress(NetworkInterface nic,String separator) {
164        try {
165            return format(nic.getHardwareAddress(),separator, Radix.HEX);
166        } catch (SocketException e) {
167            throw new RuntimeException(e);
168        }
169    }
170    /**
171     * 参见 {@link #getMacAddress(InetAddress)}
172     * @param address
173     * @param separator 格式化分隔符
174     * @return 表示MAC地址的字符串
175     */
176    public static String getMacAddress(InetAddress address,String separator) {
177        return format(getMacAddress(address),separator, Radix.HEX);        
178    }
179    private static byte invalidMacs[][] = {
180            /** VMWare */{0x00, 0x05, 0x69},             
181            /** VMWare */{0x00, 0x1C, 0x14},             
182            /** VMWare */{0x00, 0x0C, 0x29},             
183            /** VMWare */{0x00, 0x50, 0x56},             
184            /** Virtualbox */{0x08, 0x00, 0x27},         
185            /** Virtualbox */{0x0A, 0x00, 0x27},         
186            /** Virtual-PC */{0x00, 0x03, (byte)0xFF},   
187            /** Hyper-V */{0x00, 0x15, 0x5D}             
188    };
189    private static boolean isVMMac(byte[] mac) {
190        if(null == mac) {
191            return false;
192        }
193        
194        for (byte[] invalid: invalidMacs){
195            if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) {
196                return true;
197            }
198        }
199        return false;
200    }
201    /** 判断{@code host}是否为localhost */
202    public static final boolean isLoopbackAddress(String host) {
203        return "127.0.0.1".equals(host) 
204                || "::1".equals(host) 
205                || DEFAULT_HOST.equals(host);
206    }
207    /** 判断{@code address}是否为本机地址 */
208    public static final boolean isLocalhost(InetAddress address) {
209        try {
210            return address.isLoopbackAddress() 
211                    || InetAddress.getLocalHost().getHostAddress().equals( address.getHostAddress()) ;
212        } catch (UnknownHostException e) {
213            throw new RuntimeException(e);
214        }
215    }
216    /** 判断{@code address}是否为本机地址 */
217    public static final boolean isLocalhost(String host) {
218        try {
219            return isLoopbackAddress(host) || isLocalhost(InetAddress.getByName(checkNotNull(host)));
220        } catch (UnknownHostException e) {
221            return false;
222        }
223    }
224    /** 如果{@code host}为localhost转换为{@value #DEFAULT_HOST} */
225    public  static final String convertHost(String host) {
226        return isLoopbackAddress(host)? DEFAULT_HOST : host;
227    }
228    
229    /** 遍历所有物理网上绑定的地址,判断{@code address}是否为本机网卡绑定的地址 */
230    public static boolean selfBind(final InetAddress address){
231        if(isLocalhost(address)){
232            return true;
233        }
234        final Predicate<InetAddress> filter = new Predicate<InetAddress>(){
235            @Override
236            public boolean apply(InetAddress input) {
237                return input.getHostAddress().equals(address.getHostAddress());
238        }};
239        return Iterators.tryFind(getPhysicalNICs().iterator(),new Predicate<NetworkInterface>(){
240            @Override
241            public boolean apply(NetworkInterface input) {
242                return Iterators.tryFind(
243                        Iterators.forEnumeration(input.getInetAddresses()), 
244                        filter).isPresent();
245            }}).isPresent();
246    }
247    /** see also {@link #selfBind(InetAddress)} */
248    public static boolean selfBind(String host){
249        try {
250            return selfBind(InetAddress.getByName(host));
251        } catch (UnknownHostException e) {
252            return false;
253        }
254    }        
255}