1/*
2 * Copyright (c) 2013, 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
24/* @test
25 * @bug 8014499
26 * @summary Test for interference when two sockets are bound to the same
27 *          port but joined to different multicast groups
28 * @run main Promiscuous
29 * @run main/othervm -Djava.net.preferIPv4Stack=true Promiscuous
30 */
31
32import java.io.IOException;
33import static java.lang.System.out;
34import java.net.*;
35
36public class Promiscuous {
37
38    static final int TIMEOUT =  5 * 1000; // 5 secs
39    static int id = 1000;
40
41    static void receive(MulticastSocket mc, boolean datagramExpected, int id)
42        throws IOException
43    {
44        byte[] ba = new byte[100];
45        DatagramPacket p = new DatagramPacket(ba, ba.length);
46        try {
47            mc.receive(p);
48            int recvId = Integer.parseInt(
49                    new String(p.getData(), 0, p.getLength(), "UTF-8"));
50            if (datagramExpected) {
51                if (recvId != id)
52                    throw new RuntimeException("Unexpected id, got " + recvId
53                                               + ", expected: " + id);
54                out.printf("Received message as expected, %s\n", p.getAddress());
55            } else {
56                throw new RuntimeException("Unexpected message received, "
57                                           + p.getAddress());
58            }
59        } catch (SocketTimeoutException e) {
60            if (datagramExpected)
61                throw new RuntimeException("Expected message not received, "
62                                            + e.getMessage());
63            else
64                out.printf("Message not received, as expected\n");
65        }
66    }
67
68    static void test(InetAddress group1, InetAddress group2)
69        throws IOException
70    {
71        try (MulticastSocket mc1 = new MulticastSocket();
72             MulticastSocket mc2 = new MulticastSocket(mc1.getLocalPort());
73             DatagramSocket ds = new DatagramSocket()) {
74            final int port = mc1.getLocalPort();
75            out.printf("Using port: %d\n", port);
76
77            mc1.setSoTimeout(TIMEOUT);
78            mc2.setSoTimeout(TIMEOUT);
79            int nextId = id;
80            byte[] msg = Integer.toString(nextId).getBytes("UTF-8");
81            DatagramPacket p = new DatagramPacket(msg, msg.length);
82            p.setAddress(group1);
83            p.setPort(port);
84
85            mc1.joinGroup(group1);
86            out.printf("mc1 joined the MC group: %s\n", group1);
87            mc2.joinGroup(group2);
88            out.printf("mc2 joined the MC group: %s\n", group2);
89
90            out.printf("Sending datagram to: %s/%d\n", group1, port);
91            ds.send(p);
92
93            // the packet should be received by mc1 only
94            receive(mc1, true, nextId);
95            receive(mc2, false, 0);
96
97            nextId = ++id;
98            msg = Integer.toString(nextId).getBytes("UTF-8");
99            p = new DatagramPacket(msg, msg.length);
100            p.setAddress(group2);
101            p.setPort(port);
102
103            out.printf("Sending datagram to: %s/%d\n", group2, port);
104            ds.send(p);
105
106            // the packet should be received by mc2 only
107            receive(mc2, true, nextId);
108            receive(mc1, false, 0);
109
110            mc1.leaveGroup(group1);
111            mc2.leaveGroup(group2);
112        }
113    }
114
115    public static void main(String args[]) throws IOException {
116        String os = System.getProperty("os.name");
117
118        // Requires IP_MULTICAST_ALL on Linux (new since 2.6.31) so skip
119        // on older kernels. Note that we skip on <= version 3 to keep the
120        // parsing simple
121        if (os.equals("Linux")) {
122            String osversion = System.getProperty("os.version");
123            String[] vers = osversion.split("\\.", 0);
124            int major = Integer.parseInt(vers[0]);
125            if (major < 3) {
126                System.out.format("Kernel version is %s, test skipped%n", osversion);
127                return;
128            }
129        }
130
131        // multicast groups used for the test
132        InetAddress ip4Group1 = InetAddress.getByName("224.7.8.9");
133        InetAddress ip4Group2 = InetAddress.getByName("225.4.5.6");
134
135        test(ip4Group1, ip4Group2);
136    }
137}
138