1/*
2 * Copyright (c) 2003, 2016, 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
24import java.net.*;
25import java.io.*;
26import java.util.*;
27
28public class Tests {
29
30    static final boolean isWindows =
31            System.getProperty("os.name").startsWith("Windows");
32    static final boolean isMacOS =
33            System.getProperty("os.name").contains("OS X");
34
35    /**
36     * performs a simple exchange of data between the two sockets
37     * and throws an exception if there is any problem.
38     */
39    public static void simpleDataExchange (Socket s1, Socket s2)
40        throws Exception {
41
42        InputStream i1 = s1.getInputStream();
43        InputStream i2 = s2.getInputStream();
44        OutputStream o1 = s1.getOutputStream();
45        OutputStream o2 = s2.getOutputStream();
46
47        startSimpleWriter("SimpleWriter-1", o1, 100);
48        startSimpleWriter("SimpleWriter-2", o2, 200);
49        simpleRead (i2, 100);
50        simpleRead (i1, 200);
51    }
52
53    static void startSimpleWriter(String threadName, final OutputStream os, final int start) {
54        (new Thread(new Runnable() {
55            public void run() {
56                try { simpleWrite(os, start); }
57                catch (Exception e) {unexpected(e); }
58            }}, threadName)).start();
59    }
60
61    static void unexpected(Exception e ) {
62        System.out.println("Unexcepted Exception: " + e);
63        e.printStackTrace();
64    }
65
66    /**
67     * Send a packet from s1 to s2 (ia2/s2.localPort) and check it
68     * Send a packet from s2 to s1 (ia1/s1.localPort) and check it
69     */
70    public static void simpleDataExchange (DatagramSocket s1, InetAddress ia1,
71                                           DatagramSocket s2, InetAddress ia2)
72        throws Exception {
73
74        SocketAddress dest1 = new InetSocketAddress (ia1, s1.getLocalPort());
75        dprintln ("dest1 = " + dest1);
76        SocketAddress dest2 = new InetSocketAddress (ia2, s2.getLocalPort());
77        dprintln ("dest2 = " + dest2);
78
79        byte[] ba = "Hello world".getBytes();
80        byte[] bb = "HELLO WORLD1".getBytes();
81        DatagramPacket p1 = new DatagramPacket (ba, ba.length, dest1);
82        DatagramPacket p2 = new DatagramPacket (ba, ba.length, dest2);
83
84        DatagramPacket r1 = new DatagramPacket (new byte[256], 256);
85        DatagramPacket r2 = new DatagramPacket (new byte[256], 256);
86
87        s2.send (p1);
88        s1.send (p2);
89        s1.receive (r1);
90        s2.receive (r2);
91        comparePackets (p1, r1);
92        comparePackets (p2, r2);
93    }
94
95    /**
96     * Send a packet from s1 to s2 (ia2/s2.localPort) and send same packet
97     * back from s2 to sender. Check s1 receives original packet
98     */
99
100    public static void datagramEcho (DatagramSocket s1, DatagramSocket s2,
101                                     InetAddress ia2)
102        throws Exception {
103
104        byte[] ba = "Hello world".getBytes();
105        DatagramPacket p1;
106
107        SocketAddress dest2 = null;
108        if (ia2 != null) {
109            dest2 = new InetSocketAddress (ia2, s2.getLocalPort());
110            p1 = new DatagramPacket (ba, ba.length, dest2);
111        } else {
112            p1 = new DatagramPacket (ba, ba.length);
113        }
114
115        dprintln ("dest2 = " + dest2);
116
117
118        DatagramPacket r1 = new DatagramPacket (new byte[256], 256);
119        DatagramPacket r2 = new DatagramPacket (new byte[256], 256);
120
121        s1.send (p1);
122        s2.receive (r1);
123        s2.send (r1);
124        s1.receive (r2);
125        comparePackets (p1, r1);
126        comparePackets (p1, r2);
127    }
128
129    public static void comparePackets (DatagramPacket p1, DatagramPacket p2)
130        throws Exception {
131
132        byte[] b1 = p1.getData();
133        byte[] b2 = p2.getData();
134        int len = p1.getLength () > p2.getLength() ? p2.getLength()
135                                                   : p1.getLength();
136        for (int i=0; i<len; i++) {
137            if (b1[i] != b2[i]) {
138                throw new Exception ("packets not the same");
139            }
140        }
141    }
142
143    /* check the time got is within 50% of the time expected */
144    public static void checkTime (long got, long expected) {
145        checkTime(got, expected, expected);
146    }
147
148    /* check the time got is between start and end, given 50% tolerance */
149    public static void checkTime(long got, long start, long end) {
150        dprintln("checkTime: got = " + got + " start = " + start + " end = " + end);
151        long upper = end + (end / 2);
152        long lower = start - (start / 2);
153        if (got > upper || got < lower) {
154            throw new RuntimeException("checkTime failed: got " + got
155                    + ", expected between " + start + " and " + end);
156        }
157    }
158
159    static boolean debug = false;
160
161    public static void checkDebug (String[] args) {
162        debug = args.length > 0 && args[0].equals("-d");
163    }
164
165    public static void dprint (String s) {
166        if (debug) {
167            System.out.print (s);
168        }
169    }
170
171    public static void dprintln (String s) {
172        if (debug) {
173            System.out.println (s);
174        }
175    }
176
177    static int numberInterfaces () {
178        try {
179            Enumeration ifs = NetworkInterface.getNetworkInterfaces();
180            int nifs=0;
181            while (ifs.hasMoreElements()) {
182                nifs++;
183                ifs.nextElement();
184            }
185            return nifs;
186        } catch (SocketException e) {
187            return 0;
188        }
189    }
190
191    public static Enumeration ipv4Addresses() {
192        return new AddrEnum (Inet4Address.class);
193    }
194
195    public static Inet4Address getFirstLocalIPv4Address () {
196        Enumeration e = ipv4Addresses();
197        if (!e.hasMoreElements()) {
198            return null;
199        }
200        return (Inet4Address)e.nextElement();
201    }
202
203    public static Inet6Address getFirstLocalIPv6Address () {
204        Enumeration e = ipv6Addresses();
205        if (!e.hasMoreElements()) {
206            return null;
207        }
208        return (Inet6Address)e.nextElement();
209    }
210
211    public static Enumeration ipv6Addresses() {
212        return new AddrEnum (Inet6Address.class);
213    }
214
215    /* enumerates the Inet4Addresses or Inet6Addresses on the system */
216
217    private static class AddrEnum implements Enumeration {
218
219        Enumeration ifs;
220        NetworkInterface currIf = null;
221        InetAddress nextAddr=null;
222        Enumeration addrs=null;
223        Class filter;
224
225        static final byte[] fe80_loopback = new byte [] {
226            (byte)0xfe,(byte)0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1
227        };
228
229        AddrEnum (Class filter) {
230            this.filter = filter;
231            try {
232                ifs = NetworkInterface.getNetworkInterfaces();
233            } catch (SocketException e) {}
234        }
235
236        public boolean hasMoreElements () {
237            if (nextAddr == null) {
238                nextAddr = getNext();
239            }
240            return (nextAddr != null);
241        }
242
243        public Object nextElement () {
244            if (!hasMoreElements()) {
245                throw new NoSuchElementException ("no more addresses");
246            }
247            Object next = nextAddr;
248            nextAddr = null;
249            return next;
250        }
251
252        private InetAddress getNext() {
253            while (true) {
254                if (currIf == null) {
255                    currIf = getNextIf();
256                    if (currIf == null) {
257                        return null;
258                    }
259                    addrs = currIf.getInetAddresses();
260                }
261                while (addrs.hasMoreElements()) {
262                    InetAddress addr = (InetAddress) addrs.nextElement();
263                    if (filter.isInstance (addr) && !addr.isLoopbackAddress()
264                            && !addr.isAnyLocalAddress()) {
265                        if (Arrays.equals (addr.getAddress(), fe80_loopback)) {
266                            continue;
267                        }
268                        return addr;
269                    }
270                }
271                currIf = null;
272            }
273        }
274
275        private NetworkInterface getNextIf () {
276            if (ifs != null) {
277                while (ifs.hasMoreElements()) {
278                    NetworkInterface nic = (NetworkInterface)ifs.nextElement();
279                    // Skip (Windows)Teredo Tunneling Pseudo-Interface
280                    if (isWindows) {
281                        String dName = nic.getDisplayName();
282                        if (dName != null && dName.contains("Teredo"))
283                            continue;
284                    } else if (isMacOS && nic.getName().contains("awdl")) {
285                        continue;
286                    }
287                    try {
288                        if (nic.isUp() && !nic.isLoopback())
289                            return nic;
290                    } catch (SocketException e) {
291                        // ignore
292                    }
293                }
294            }
295
296            return null;
297        }
298    }
299
300    /**
301     * Throws a RuntimeException if the boolean condition is false
302     */
303    public static void t_assert (boolean assertion) {
304        if (assertion) {
305            return;
306        }
307        Throwable t = new Throwable();
308        StackTraceElement[] strace = t.getStackTrace();
309        String msg = "Assertion failed at: " + strace[1].toString();
310        throw new RuntimeException (msg);
311    }
312
313    private static void simpleRead (InputStream is, int start) throws Exception {
314        byte b[] = new byte [2];
315        for (int i=start; i<start+100; i++) {
316            int x = is.read (b);
317            if (x == 1) {
318                x += is.read (b,1,1);
319            }
320            if (x!=2) {
321                throw new Exception ("read error");
322            }
323            int r = bytes (b[0], b[1]);
324            if (r != i) {
325                throw new Exception ("read " + r + " expected " +i);
326            }
327        }
328    }
329
330    /* convert signed bytes to unisigned int */
331    private static int bytes (byte b1, byte b2) {
332        int i1 = (int)b1 & 0xFF;
333        int i2 = (int)b2 & 0xFF;
334        return i1 * 256 + i2;
335    }
336
337    static void simpleWrite (OutputStream os, int start) throws Exception {
338        byte b[] = new byte [2];
339        for (int i=start; i<start+100; i++) {
340            b[0] = (byte) (i / 256);
341            b[1] = (byte) (i % 256);
342            os.write (b);
343        }
344    }
345
346    private static class Runner extends Thread {
347        Runnable runnee;
348        long delay;
349
350        Runner (Runnable runnee, long delay) {
351            super();
352            this.runnee = runnee;
353            this.delay = delay;
354        }
355
356        public void run () {
357            try {
358                Thread.sleep (delay);
359                runnee.run ();
360            } catch (Exception e) {
361                e.printStackTrace();
362            }
363        }
364    }
365
366    /*
367     * Take the given Runnable and run it in a spawned thread
368     * after the given time has elapsed. runAfter() returns immediately
369     */
370    public static void runAfter (long millis, Runnable runnee) {
371        Runner runner = new Runner (runnee, millis);
372        runner.start ();
373    }
374
375    static String osname;
376
377    static {
378        osname = System.getProperty ("os.name");
379    }
380
381    static boolean isLinux () {
382        return osname.equals ("Linux");
383    }
384
385    static boolean isWindows () {
386        return osname.startsWith ("Windows");
387    }
388}
389