Package com.sun.faban.harness.util

Source Code of com.sun.faban.harness.util.InterfaceProbe

/* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://www.sun.com/cddl/cddl.html or
* install_dir/legal/LICENSE
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at install_dir/legal/LICENSE.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id$
*
* Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
*/
package com.sun.faban.harness.util;

import com.sun.faban.harness.ConfigurationException;
import java.util.concurrent.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.net.*;
import java.io.IOException;

/**
* The InterfaceProbe probes interfaces and finds the best interface to
* communicate with an IP address or host name.
*/
public class InterfaceProbe {

    Logger logger = Logger.getLogger(this.getClass().getName());
    ExecutorService threadPool = null;
    static final int TIMEOUT = 10000;
    static final int LOCAL_TIMEOUT = 5000;

    // Parallel probing is still buggy, especially for ICMP echo (root ping)
    // mode. So we'll not use it just yet. This seems like a JDK bug.
    // Once we get it working in all instances, we'll change this.
    static final int PARALLEL_THRESHOLD = Integer.MAX_VALUE;

    ArrayList<NetworkInterface> ifList;
    List<IFAddressInfo> ifAInfoList;

    /**
     * Unit tests the interface probe.
     * @param args The commmand line arguments
     */
    public static void main(String[] args) {
        try {
            ArrayList<String> hosts = new ArrayList<String>();
            for (String arg : args) {
                hosts.add(arg);
            }
            InterfaceProbe ifs = new InterfaceProbe();
            List<Route> rtes = ifs.getRoutes(hosts);
            System.out.println("destination\tiface\tifAddress\tttl\treachable");
            for (Route rte : rtes) {
                System.out.print(rte.host + '\t');
                if (rte.nif != null)
                    System.out.print(rte.nif.getDisplayName() + '\t');
                else
                    System.out.print("-\t");
                if (rte.nifAddress != null)
                    System.out.print(rte.nifAddress);
                else
                    System.out.print("-\t");
                System.out.println("\t" + rte.ttl + '\t' + rte.reachable);
            }
            System.exit(0);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        System.exit(1);
    }

    static class Route {
        String host;
        InetAddress target;
        NetworkInterface nif;
        String nifAddress;
        short ttl = 0;
        boolean reachable = false;
    }

    static class IFAddressInfo {
        NetworkInterface nif;
        InterfaceAddress nifAddress;
        short prefixLength;
        byte[] netAddress;
    }

    /**
     * .
     * @throws java.net.SocketException
     */
    public InterfaceProbe() throws SocketException {
        Enumeration<NetworkInterface> interfaces =
                NetworkInterface.getNetworkInterfaces();
        ifList = new ArrayList<NetworkInterface>();
        addInterfaces(interfaces, ifList);
        ifAInfoList = listIFAddressInfo(ifList);
    }

    /**
     * .
     * @param executor
     * @throws java.net.SocketException
     */
    public InterfaceProbe(ExecutorService executor) throws SocketException {
        this();
        threadPool = executor;
    }

    /**
     * Sets the thread pool to be used for parallel probing.
     * @param executor The thread pool
     */
    public void setExecutorService(ExecutorService executor) {
        threadPool = executor;
    }

    private List<IFAddressInfo> listIFAddressInfo(
                                            List<NetworkInterface> ifList) {
        ArrayList<IFAddressInfo> ifAInfos = new ArrayList<IFAddressInfo>();
        ifSearchLoop:
        for (NetworkInterface nif : ifList) {
            List<InterfaceAddress> ifAddresses =
                    nif.getInterfaceAddresses();
            for (InterfaceAddress ifAddress : ifAddresses) {
                if (ifAddress == null)
                    continue;
                IFAddressInfo ifAInfo = new IFAddressInfo();
                ifAInfo.nif = nif;
                ifAInfo.nifAddress = ifAddress;
                InetAddress ia = ifAddress.getAddress();
                ifAInfo.prefixLength = ifAddress.getNetworkPrefixLength();
                try {
                    ifAInfo.netAddress =
                            getNetworkAddress(ia, ifAInfo.prefixLength);
                } catch (ConfigurationException e) {
                    StringBuilder buffer = new StringBuilder();
                    buffer.append(e.getMessage()).append('\n');
                    buffer = printIfInfo(ifAInfo, buffer);
                    logger.log(Level.WARNING, buffer.toString(), e);
                    continue;
                }
                ifAInfos.add(ifAInfo);
                printIfInfo(ifAInfo);
            }
        }
        return ifAInfos;
    }

    /**
     * Fills the interface maps identifying which interface is to be used
     * to communicate to a particular host.
     * @param hosts The host list
     * @param ifMap The host to interface map to fill
     * @return The host to interface map provided, filled in
     */
    public Map<String, String> getIfMap(Collection<String> hosts,
                                        Map<String, String> ifMap) {

        // Grab only the hosts without interfaces from ifMap.
        HashSet<String> hostsToProbe = new HashSet<String>();
        for (String host : hosts) {
            String iface = ifMap.get(host);
            if (iface == null || iface.length() == 0)
                hostsToProbe.add(host);
        }

        // Obtain the routes
        List<Route> routes = getRoutes(hostsToProbe);

        // Complete the ifMap
        for (Route route : routes)
            ifMap.put(route.host, route.nifAddress);
        return ifMap;
    }

    /**
     * Obtains the route list for a list of hosts.
     * @param hosts The list of hosts
     * @return the corresponding list of routes
     */
    List<Route> getRoutes(Collection<String> hosts) {
        ArrayList<Route> routes = new ArrayList<Route>();
        if (hosts.size() < PARALLEL_THRESHOLD) {
            for (String host : hosts) {
                Route rte = getOrFindRoute(host);
                routes.add(rte);
            }
        } else {
            if (threadPool == null)
                threadPool = Executors.newCachedThreadPool();
            ArrayList<Future<Route>> futures = new ArrayList<Future<Route>>();
            for (String target : hosts)
                futures.add(threadPool.submit(new GetRouteTask(target)));
            for (Future<Route> f : futures) {
                try {
                    routes.add(f.get());
                } catch (InterruptedException e) {
                    logger.log(Level.WARNING, "Route scan interrupted", e);
                } catch (ExecutionException e) {
                    Throwable e2 = e.getCause();
                    logger.log(Level.WARNING, e2.getMessage(), e2);
                }
            }
        }
        return routes;
    }

    private Route getOrFindRoute(String host) {
        Route rte = new Route();
        rte.host = host;
        try {
            rte.target = InetAddress.getByName(host);
        } catch (UnknownHostException e) {
            logger.log(Level.WARNING, "Host " + host + " unknown!", e);
        }
        try {
            if (!rte.target.equals(InetAddress.getLocalHost())) {
                getRoute(rte);
                if (rte.nifAddress == null)
                    findRoute(rte);
            } else {
                logger.log(Level.WARNING, "localhost ignored!");
            }
        } catch (UnknownHostException e) {
            logger.log(Level.SEVERE, "localhost unknown!", e);
        }
        return rte;
    }

    class GetRouteTask implements Callable<Route> {

        String target;

        GetRouteTask(String target) {
            this.target = target;
        }

        public Route call() {
            return getOrFindRoute(target);
        }
    }


    private void findRoute(Route rte) {
        // First see whether we can even get to this system
        try {
            if (!rte.target.isReachable(TIMEOUT)) {
                return;
            }
            ArrayList<Route> routeList = new ArrayList<Route>();
            for (NetworkInterface nif : ifList) {

                // Try each interface...
                if (!rte.target.isReachable(nif, 0, TIMEOUT))
                    continue;

                Route rte2 = new Route();
                rte2.host = rte.host;
                rte2.target = rte.target;
                rte2.nif = nif;
                rte2.ttl = Short.MAX_VALUE;
                rte2.reachable = true;
                routeList.add(rte2);
            }

            if (routeList.size() == 0) {
                logger.log(Level.SEVERE, "Target is reachable but not " +
                       "reachable through any listed route. Seems like a bug!");
                return;
            }


            // If we can reach with multiple interfaces, find the best one
            selectLoop:
            while (routeList.size() > 1) {
                int listSize = routeList.size();
                for (int rteIdx = 0; rteIdx < listSize; rteIdx++) {
                    Route rte2 = routeList.get(rteIdx);
                    if (rte2.ttl == Integer.MAX_VALUE)
                        rte2.ttl = 63;
                    else if (rte2.ttl == 0)
                        break selectLoop;
                    if (!rte2.target.isReachable(rte.nif, rte.ttl, TIMEOUT)) {
                        routeList.remove(rteIdx);
                        continue selectLoop;
                    }
                    --rte2.ttl; // Keep decreasing...
                }
            }

            Route rte2 = routeList.get(0); // Even if two of them make it to 0,
            // just choose the first.

            // We populate the value, but do not change the rte reference.
            rte.nif = rte2.nif;
            rte.ttl = rte2.ttl;
            rte.reachable = rte2.reachable;

            // We assume an interface has only one ip address per type.
            List<InterfaceAddress> ifAddresses =
                                            rte.nif.getInterfaceAddresses();
            for (InterfaceAddress ifAddress : ifAddresses)
                if (ifAddress.getAddress().getAddress().length ==
                        rte.target.getAddress().length) {
                    rte.nifAddress = ifAddress.getAddress().getHostAddress();
                    break;
                }
        } catch (IOException e) {
            logger.log(Level.WARNING, "Network error trying to reach " +
                        rte.host + '!', e);
        }
    }

    private void getRoute(Route route) {

        // Scan for a matching interface
        for (IFAddressInfo ifAInfo : ifAInfoList) {
            if (ifAInfo.netAddress.length != route.target.getAddress().length)
                continue;
            byte[] targetNet;
            try {
                targetNet = getNetworkAddress(route.target,
                                              ifAInfo.prefixLength);
            } catch (ConfigurationException e) {
                StringBuilder buffer = new StringBuilder();
                buffer.append(e.getMessage()).append('\n');
                buffer = printIfInfo(ifAInfo, buffer);
                logger.log(Level.WARNING, buffer.toString(), e);
                continue;
            }
            if (Arrays.equals(ifAInfo.netAddress, targetNet)) {
                route.nif = ifAInfo.nif;
                route.nifAddress = ifAInfo.nifAddress.getAddress().
                                                            getHostAddress();
                break;
            }
        }

        // Now try to ping it through the interface.
        try {
            route.reachable =
                    route.target.isReachable(route.nif, 1, LOCAL_TIMEOUT);
        } catch (IOException e) {
            logger.log(Level.WARNING, "Network error trying to reach " +
                        route.host + '!', e);
        }
        return;
    }

    void printIfInfo(IFAddressInfo ifAInfo) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine(printIfInfo(ifAInfo, new StringBuilder()).toString());
        }
    }

    StringBuilder printIfInfo(IFAddressInfo ifAInfo, StringBuilder buffer) {
        InetAddress ia = ifAInfo.nifAddress.getAddress();
        String ifName = ifAInfo.nif.getDisplayName();
        Formatter fmt = new Formatter(buffer);
        buffer.append(ifName);
        if (ia instanceof Inet4Address) {
            buffer.append("\tv4: " + ia.getHostAddress());
            buffer.append("\n\t\tNetwork " + ifAInfo.prefixLength + " bits\n");
            if (ifAInfo.netAddress != null) {
                int[] netAddressI = new int[ifAInfo.netAddress.length];
                for (int i = 0; i < netAddressI.length; i++) {
                    if (ifAInfo.netAddress[i] < 0) {
                        netAddressI[i] = 256 + ifAInfo.netAddress[i];
                    } else {
                        netAddressI[i] = ifAInfo.netAddress[i];
                    }
                }
                fmt.format("\t\tNet address: %d", netAddressI[0]);
                for (int i = 1; i < ifAInfo.netAddress.length; i++) {
                    fmt.format(".%d", netAddressI[i]);
                }
                buffer.append('\n');
            } else {
                buffer.append("\t\tNet address: null\n");
            }
        } else if (ia instanceof Inet6Address) {
            buffer.append("\tv6: " + ia.getHostAddress());
            buffer.append("\n\t\tNetwork " + ifAInfo.prefixLength + " bits\n");
            if (ifAInfo.netAddress != null) {
            int[] netAddressI = new int[ifAInfo.netAddress.length / 2];
            for (int i = 0; i < netAddressI.length; i++) {
                int au = ifAInfo.netAddress[2 * i];
                if (au < 0)
                    au += 256;
                au <<= 8;
                int au1 = ifAInfo.netAddress[2 * i + 1];
                if (au1 < 0)
                    au1 += 256;
                au |= au1;
                netAddressI[i] = au;
            }
            fmt.format("\t\tNet address: %x", netAddressI[0]);
            for (int i = 1; i < netAddressI.length; i++)
                fmt.format(":%x", netAddressI[i]);
            buffer.append('\n');
            } else {
                buffer.append("\t\tNet address: null\n");
            }
        }
        return buffer;
    }

    private byte[] getNetworkAddress(InetAddress ia, short prefixLen)
            throws ConfigurationException {
        byte[] byteAddress = ia.getAddress();
        short networkBytes = (short) (prefixLen / 8);
        if (networkBytes > byteAddress.length) {
            throw new ConfigurationException(
            "Netmask too long. Network address " + ia + " has " +
                    prefixLen + "bit netmask while having " +
                    byteAddress.length + "bytes in the address. " +
                    "The address is a " + ia.getClass().getName());
        }
        byte[] netAddress = new byte[byteAddress.length];
        int bytePos = 0;
        for (; bytePos < networkBytes; bytePos++)
            netAddress[bytePos] = byteAddress[bytePos];
        short networkBits = (short) (prefixLen % 8);
        if (networkBits > 0) {
            byte mask = Byte.MIN_VALUE;
            for (int bitPos = 1; bitPos < networkBits; bitPos++)
                mask |= mask >>> 1;
            netAddress[bytePos] = (byte) (byteAddress[bytePos] & mask);
        }
        return netAddress;
    }

    private void addInterfaces(Enumeration<NetworkInterface> interfaces,
                                     ArrayList<NetworkInterface> ifList)
            throws SocketException {
        while (interfaces.hasMoreElements()) {
            NetworkInterface nif = interfaces.nextElement();
            if (nif.isUp() && !nif.isLoopback()) {
                ifList.add(nif);
                addInterfaces(nif.getSubInterfaces(), ifList);
            }
        }
    }
}
TOP

Related Classes of com.sun.faban.harness.util.InterfaceProbe

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.