NetworkConfiguration.java revision 2628:190dbd51ed68
1/*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24package jdk.test.lib;
25
26import java.io.PrintStream;
27import java.io.UncheckedIOException;
28import java.io.IOException;
29import java.net.Inet4Address;
30import java.net.Inet6Address;
31import java.net.InetAddress;
32import java.net.NetworkInterface;
33import java.util.Arrays;
34import java.util.HashMap;
35import java.util.LinkedList;
36import java.util.List;
37import java.util.Map;
38import java.util.function.Predicate;
39import java.util.stream.Collectors;
40import java.util.stream.Stream;
41import static java.net.NetworkInterface.getNetworkInterfaces;
42import static java.util.Collections.list;
43
44/**
45 * Helper class for retrieving network interfaces and local addresses
46 * suitable for testing.
47 */
48public class NetworkConfiguration {
49
50    private Map<NetworkInterface,List<Inet4Address>> ip4Interfaces;
51    private Map<NetworkInterface,List<Inet6Address>> ip6Interfaces;
52
53    private NetworkConfiguration(
54            Map<NetworkInterface,List<Inet4Address>> ip4Interfaces,
55            Map<NetworkInterface,List<Inet6Address>> ip6Interfaces) {
56        this.ip4Interfaces = ip4Interfaces;
57        this.ip6Interfaces = ip6Interfaces;
58    }
59
60    /**
61     * Returns a stream of interfaces suitable for functional tests.
62     */
63    public Stream<NetworkInterface> interfaces() {
64        return Stream.concat(ip4Interfaces(), ip6Interfaces())
65                     .distinct();
66    }
67
68    /**
69     * Returns a stream of interfaces suitable for IPv4 functional tests.
70     */
71    public Stream<NetworkInterface> ip4Interfaces() {
72        return ip4Interfaces.keySet()
73                            .stream()
74                            .filter(NetworkConfiguration::isNotExcludedInterface)
75                            .filter(hasIp4Addresses);
76    }
77
78    /**
79     * Returns a stream of interfaces suitable for IPv6 functional tests.
80     */
81    public Stream<NetworkInterface> ip6Interfaces() {
82        return ip6Interfaces.keySet()
83                            .stream()
84                            .filter(NetworkConfiguration::isNotExcludedInterface)
85                            .filter(hasIp6Addresses);
86    }
87
88    private static boolean isNotExcludedInterface(NetworkInterface nif) {
89        if (Platform.isOSX() && nif.getName().contains("awdl")) {
90            return false;
91        }
92        String dName = nif.getDisplayName();
93        if (Platform.isWindows() && dName != null && dName.contains("Teredo")) {
94            return false;
95        }
96        return true;
97    }
98
99    private final Predicate<NetworkInterface> hasIp4Addresses = nif ->
100            ip4Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
101
102    private final Predicate<NetworkInterface> hasIp6Addresses = nif ->
103            ip6Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
104
105
106    /**
107     * Returns a stream of interfaces suitable for IPv4 multicast tests.
108     */
109    public Stream<NetworkInterface> ip4MulticastInterfaces() {
110        return ip4Interfaces().filter(supportsIp4Multicast);
111    }
112
113    /**
114     * Returns a stream of interfaces suitable for IPv6 multicast tests.
115     */
116    public Stream<NetworkInterface> ip6MulticastInterfaces() {
117        return ip6Interfaces().filter(supportsIp6Multicast);
118    }
119
120    private final Predicate<NetworkInterface> supportsIp4Multicast = nif -> {
121        try {
122            if (!nif.supportsMulticast() || nif.isLoopback()) {
123                return false;
124            }
125            return hasIp4Addresses.test(nif);
126        } catch (IOException e) {
127            throw new UncheckedIOException(e);
128        }
129    };
130
131    private final Predicate<NetworkInterface> supportsIp6Multicast = nif -> {
132        try {
133            if (!nif.supportsMulticast() || nif.isLoopback()) {
134                return false;
135            }
136
137            return hasIp6Addresses.test(nif);
138        } catch (IOException e) {
139            throw new UncheckedIOException(e);
140        }
141    };
142
143    /**
144     * Returns all addresses on all "functional" interfaces.
145     */
146    public Stream<InetAddress> addresses(NetworkInterface nif) {
147        return Stream.concat(ip4Interfaces.get(nif).stream(),
148                             ip6Interfaces.get(nif).stream());
149    }
150
151    /**
152     * Returns all IPv4 addresses on all "functional" interfaces.
153     */
154    public Stream<Inet4Address> ip4Addresses() {
155        return ip4Interfaces().flatMap(this::ip4Addresses);
156    }
157
158    /**
159     * Returns all IPv6 addresses on all "functional" interfaces.
160     */
161    public Stream<Inet6Address> ip6Addresses() {
162        return ip6Interfaces().flatMap(this::ip6Addresses);
163    }
164
165    /**
166     * Returns all IPv4 addresses the given interface.
167     */
168    public Stream<Inet4Address> ip4Addresses(NetworkInterface nif) {
169        return ip4Interfaces.get(nif).stream();
170    }
171
172    /**
173     * Returns all IPv6 addresses for the given interface.
174     */
175    public Stream<Inet6Address> ip6Addresses(NetworkInterface nif) {
176        return ip6Interfaces.get(nif).stream();
177    }
178
179    /**
180     * Return a NetworkConfiguration instance.
181     */
182    public static NetworkConfiguration probe() throws IOException {
183        Map<NetworkInterface, List<Inet4Address>> ip4Interfaces = new HashMap<>();
184        Map<NetworkInterface, List<Inet6Address>> ip6Interfaces = new HashMap<>();
185
186        List<NetworkInterface> nifs = list(getNetworkInterfaces());
187        for (NetworkInterface nif : nifs) {
188            // ignore interfaces that are down
189            if (!nif.isUp() || nif.isPointToPoint()) {
190                continue;
191            }
192
193            List<Inet4Address> ip4Addresses = new LinkedList<>();
194            List<Inet6Address> ip6Addresses = new LinkedList<>();
195            ip4Interfaces.put(nif, ip4Addresses);
196            ip6Interfaces.put(nif, ip6Addresses);
197            for (InetAddress addr : list(nif.getInetAddresses())) {
198                if (addr instanceof Inet4Address) {
199                    ip4Addresses.add((Inet4Address) addr);
200                } else if (addr instanceof Inet6Address) {
201                    ip6Addresses.add((Inet6Address) addr);
202                }
203            }
204        }
205        return new NetworkConfiguration(ip4Interfaces, ip6Interfaces);
206    }
207
208    @Override
209    public String toString() {
210        return interfaces().map(NetworkConfiguration::interfaceInformation)
211                           .collect(Collectors.joining());
212    }
213
214    /** Returns detailed information for the given interface. */
215    public static String interfaceInformation(NetworkInterface nif) {
216        StringBuilder sb = new StringBuilder();
217        try {
218            sb.append("Display name: ")
219              .append(nif.getDisplayName())
220              .append("\n");
221            sb.append("Name: ")
222              .append(nif.getName())
223              .append("\n");
224            for (InetAddress inetAddress : list(nif.getInetAddresses())) {
225                sb.append("InetAddress: ")
226                  .append(inetAddress)
227                  .append("\n");
228            }
229            sb.append("Up? ")
230              .append(nif.isUp())
231              .append("\n");
232            sb.append("Loopback? ")
233              .append(nif.isLoopback())
234              .append("\n");
235            sb.append("PointToPoint? ")
236              .append(nif.isPointToPoint())
237              .append("\n");
238            sb.append("Supports multicast? ")
239              .append(nif.supportsMulticast())
240              .append("\n");
241            sb.append("Virtual? ")
242              .append(nif.isVirtual())
243              .append("\n");
244            sb.append("Hardware address: ")
245              .append(Arrays.toString(nif.getHardwareAddress()))
246              .append("\n");
247            sb.append("MTU: ")
248              .append(nif.getMTU())
249              .append("\n");
250            sb.append("Index: ")
251              .append(nif.getIndex())
252              .append("\n");
253            sb.append("\n");
254            return sb.toString();
255        } catch (IOException e) {
256            throw new UncheckedIOException(e);
257        }
258    }
259
260    /** Prints all the system interface information to the give stream. */
261    public static void printSystemConfiguration(PrintStream out) {
262        try {
263            out.println("*** all system network interface configuration ***");
264            for (NetworkInterface nif : list(getNetworkInterfaces())) {
265                out.print(interfaceInformation(nif));
266            }
267            out.println("*** end ***");
268        } catch (IOException e) {
269            throw new UncheckedIOException(e);
270        }
271    }
272}
273