1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.tests.java.net;
19
20import java.io.IOException;
21import java.net.BindException;
22import java.net.DatagramPacket;
23import java.net.Inet4Address;
24import java.net.Inet6Address;
25import java.net.InetAddress;
26import java.net.InetSocketAddress;
27import java.net.MulticastSocket;
28import java.net.NetworkInterface;
29import java.net.SocketAddress;
30import java.net.SocketException;
31import java.net.SocketTimeoutException;
32import java.util.ArrayList;
33import java.util.Enumeration;
34import java.util.List;
35
36public class MulticastSocketTest extends junit.framework.TestCase {
37
38    private static InetAddress lookup(String s) {
39        try {
40            return InetAddress.getByName(s);
41        } catch (IOException ex) {
42            throw new RuntimeException(ex);
43        }
44    }
45
46    // These IP addresses aren't inherently "good" or "bad"; they're just used like that.
47    // We use the "good" addresses for our actual group, and the "bad" addresses are for
48    // a group that we won't actually set up.
49
50    private static InetAddress GOOD_IPv4 = lookup("224.0.0.3");
51    private static InetAddress BAD_IPv4 = lookup("224.0.0.4");
52    private static InetAddress GOOD_IPv6 = lookup("ff05::7:7");
53    private static InetAddress BAD_IPv6 = lookup("ff05::7:8");
54
55    private NetworkInterface loopbackInterface;
56    private NetworkInterface ipv4NetworkInterface;
57    private NetworkInterface ipv6NetworkInterface;
58    private boolean supportsMulticast;
59
60    @Override
61    protected void setUp() throws Exception {
62        // The loopback interface isn't actually useful for sending/receiving multicast messages
63        // but it can be used as a dummy for tests where that does not matter.
64        loopbackInterface = NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress());
65        assertNotNull(loopbackInterface);
66        assertTrue(loopbackInterface.isLoopback());
67        assertFalse(loopbackInterface.supportsMulticast());
68
69        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
70        assertNotNull(interfaces);
71
72        // Determine if the device is marked to support multicast or not. If this propery is not
73        // set we assume the device has an interface capable of supporting multicast.
74        supportsMulticast = Boolean.valueOf(
75                System.getProperty("android.cts.device.multicast", "true"));
76        if (!supportsMulticast) {
77            return;
78        }
79
80        while (interfaces.hasMoreElements()
81                && (ipv4NetworkInterface == null || ipv6NetworkInterface == null)) {
82            NetworkInterface nextInterface = interfaces.nextElement();
83            if (willWorkForMulticast(nextInterface)) {
84                Enumeration<InetAddress> addresses = nextInterface.getInetAddresses();
85                while (addresses.hasMoreElements()) {
86                    final InetAddress nextAddress = addresses.nextElement();
87                    if (nextAddress instanceof Inet6Address && ipv6NetworkInterface == null) {
88                        ipv6NetworkInterface = nextInterface;
89                    } else if (nextAddress instanceof Inet4Address
90                            && ipv4NetworkInterface == null) {
91                        ipv4NetworkInterface = nextInterface;
92                    }
93                }
94            }
95        }
96        assertTrue("Test environment must have at least one interface capable of multicast for IPv4"
97                        + " and IPv6",
98                ipv4NetworkInterface != null && ipv6NetworkInterface != null);
99    }
100
101    public void test_Constructor() throws IOException {
102        if (!supportsMulticast) {
103            return;
104        }
105        // Regression test for 497.
106        MulticastSocket s = new MulticastSocket();
107        // Regression test for Harmony-1162.
108        assertTrue(s.getReuseAddress());
109
110        s.close();
111    }
112
113    public void test_ConstructorI() throws IOException {
114        if (!supportsMulticast) {
115            return;
116        }
117        MulticastSocket orig = new MulticastSocket();
118        int port = orig.getLocalPort();
119        orig.close();
120
121        MulticastSocket dup = new MulticastSocket(port);
122        // Regression test for Harmony-1162.
123        assertTrue(dup.getReuseAddress());
124        dup.close();
125    }
126
127    public void test_getInterface() throws Exception {
128        if (!supportsMulticast) {
129            return;
130        }
131        // Validate that we get the expected response when one was not set.
132        MulticastSocket mss = new MulticastSocket(0);
133        // We expect an ANY address in this case.
134        assertTrue(mss.getInterface().isAnyLocalAddress());
135
136        // Validate that we get the expected response when we set via setInterface.
137        Enumeration addresses = ipv4NetworkInterface.getInetAddresses();
138        if (addresses.hasMoreElements()) {
139            InetAddress firstAddress = (InetAddress) addresses.nextElement();
140            mss.setInterface(firstAddress);
141            assertEquals("getNetworkInterface did not return interface set by setInterface",
142                    firstAddress, mss.getInterface());
143
144            mss.close();
145            mss = new MulticastSocket(0);
146            mss.setNetworkInterface(ipv4NetworkInterface);
147            assertEquals("getInterface did not return interface set by setNetworkInterface",
148                    ipv4NetworkInterface, NetworkInterface.getByInetAddress(mss.getInterface()));
149        }
150
151        mss.close();
152    }
153
154    public void test_getNetworkInterface() throws IOException {
155        if (!supportsMulticast) {
156            return;
157        }
158        // Validate that we get the expected response when one was not set.
159        MulticastSocket mss = new MulticastSocket(0);
160        NetworkInterface theInterface = mss.getNetworkInterface();
161        assertTrue(
162                "network interface returned wrong network interface when not set:" + theInterface,
163                theInterface.getInetAddresses().hasMoreElements());
164        InetAddress firstAddress = theInterface.getInetAddresses().nextElement();
165        // Validate we the first address in the network interface is the ANY address.
166        assertTrue(firstAddress.isAnyLocalAddress());
167
168        mss.setNetworkInterface(ipv4NetworkInterface);
169        assertEquals("getNetworkInterface did not return interface set by setNeworkInterface",
170                ipv4NetworkInterface, mss.getNetworkInterface());
171
172        mss.setNetworkInterface(loopbackInterface);
173        assertEquals(
174                "getNetworkInterface did not return network interface set by second"
175                        + " setNetworkInterface call",
176                loopbackInterface, mss.getNetworkInterface());
177        mss.close();
178
179        if (ipv6NetworkInterface != null) {
180            mss = new MulticastSocket(0);
181            mss.setNetworkInterface(ipv6NetworkInterface);
182            assertEquals("getNetworkInterface did not return interface set by setNeworkInterface",
183                    ipv6NetworkInterface, mss.getNetworkInterface());
184            mss.close();
185        }
186
187        // Validate that we get the expected response when we set via setInterface.
188        mss = new MulticastSocket(0);
189        Enumeration addresses = ipv4NetworkInterface.getInetAddresses();
190        if (addresses.hasMoreElements()) {
191            firstAddress = (InetAddress) addresses.nextElement();
192            mss.setInterface(firstAddress);
193            assertEquals("getNetworkInterface did not return interface set by setInterface",
194                    ipv4NetworkInterface, mss.getNetworkInterface());
195        }
196        mss.close();
197    }
198
199    public void test_getTimeToLive() throws Exception {
200        if (!supportsMulticast) {
201            return;
202        }
203        MulticastSocket mss = new MulticastSocket();
204        mss.setTimeToLive(120);
205        assertEquals("Returned incorrect 1st TTL", 120, mss.getTimeToLive());
206        mss.setTimeToLive(220);
207        assertEquals("Returned incorrect 2nd TTL", 220, mss.getTimeToLive());
208        mss.close();
209    }
210
211    public void test_getTTL() throws Exception {
212        if (!supportsMulticast) {
213            return;
214        }
215        MulticastSocket mss = new MulticastSocket();
216        mss.setTTL((byte) 120);
217        assertEquals("Returned incorrect TTL", 120, mss.getTTL());
218        mss.close();
219    }
220
221    public void test_joinGroupLjava_net_InetAddress_IPv4() throws Exception {
222        if (!supportsMulticast) {
223            return;
224        }
225        test_joinGroupLjava_net_InetAddress(GOOD_IPv4);
226    }
227
228    public void test_joinGroupLjava_net_InetAddress_IPv6() throws Exception {
229        if (!supportsMulticast) {
230            return;
231        }
232        test_joinGroupLjava_net_InetAddress(GOOD_IPv6);
233    }
234
235    private void test_joinGroupLjava_net_InetAddress(InetAddress group) throws Exception {
236        MulticastSocket receivingSocket = createReceivingSocket(0);
237        receivingSocket.joinGroup(group);
238
239        String msg = "Hello World";
240        MulticastSocket sendingSocket = new MulticastSocket(receivingSocket.getLocalPort());
241        InetSocketAddress groupAddress =
242                new InetSocketAddress(group, receivingSocket.getLocalPort());
243        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
244        sendingSocket.send(sdp, (byte) 10 /* ttl */);
245
246        DatagramPacket rdp = createReceiveDatagramPacket();
247        receivingSocket.receive(rdp);
248        String receivedMessage = extractMessage(rdp);
249        assertEquals("Group member did not recv data", msg, receivedMessage);
250
251        sendingSocket.close();
252        receivingSocket.close();
253    }
254
255    public void test_joinGroup_null_null() throws Exception {
256        if (!supportsMulticast) {
257            return;
258        }
259        MulticastSocket mss = new MulticastSocket(0);
260        try {
261            mss.joinGroup(null, null);
262            fail();
263        } catch (IllegalArgumentException expected) {
264        }
265        mss.close();
266    }
267
268    public void test_joinGroup_non_multicast_address_IPv4() throws Exception {
269        if (!supportsMulticast) {
270            return;
271        }
272        MulticastSocket mss = new MulticastSocket(0);
273        try {
274            mss.joinGroup(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0), null);
275            fail();
276        } catch (IOException expected) {
277        }
278        mss.close();
279    }
280
281    public void test_joinGroup_non_multicast_address_IPv6() throws Exception {
282        if (!supportsMulticast) {
283            return;
284        }
285        MulticastSocket mss = new MulticastSocket(0);
286        try {
287            mss.joinGroup(new InetSocketAddress(InetAddress.getByName("::1"), 0), null);
288            fail();
289        } catch (IOException expected) {
290        }
291        mss.close();
292    }
293
294    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
295            throws Exception {
296        if (!supportsMulticast) {
297            return;
298        }
299        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
300                ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
301    }
302
303    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
304            throws Exception {
305        if (!supportsMulticast) {
306            return;
307        }
308        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
309                ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
310    }
311
312    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface()
313            throws Exception {
314        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv4, BAD_IPv4);
315    }
316
317    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6_nullInterface()
318            throws Exception {
319        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv6, BAD_IPv6);
320    }
321
322    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
323            NetworkInterface networkInterface, InetAddress group, InetAddress group2)
324            throws Exception {
325        // Create the sending socket and specify the interface to use as needed (otherwise use the
326        // default).
327        MulticastSocket sendingSocket = new MulticastSocket(0);
328        if (networkInterface != null) {
329            sendingSocket.setNetworkInterface(networkInterface);
330        }
331        sendingSocket.setTimeToLive(2);
332
333        MulticastSocket receivingSocket = createReceivingSocket(0);
334        InetSocketAddress groupAddress =
335                new InetSocketAddress(group, receivingSocket.getLocalPort());
336        // Join the group. A null network interface is valid and means "use default".
337        receivingSocket.joinGroup(groupAddress, networkInterface);
338
339        String msg = "Hello World";
340        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
341        sendingSocket.send(sdp);
342
343        DatagramPacket rdp = createReceiveDatagramPacket();
344        receivingSocket.receive(rdp);
345        // Now validate that we received the data as expected.
346        assertEquals("Group member did not recv data", msg, extractMessage(rdp));
347        receivingSocket.close();
348        sendingSocket.close();
349
350        // Create the sending socket and specify the interface to use as needed (otherwise use the
351        // default).
352        sendingSocket = new MulticastSocket(0);
353        if (networkInterface != null) {
354            sendingSocket.setNetworkInterface(networkInterface);
355        }
356        sendingSocket.setTimeToLive(10);
357
358        receivingSocket = createReceivingSocket(0);
359        groupAddress = new InetSocketAddress(group, receivingSocket.getLocalPort());
360        // Join the group. A null network interface is valid and means "use default".
361        receivingSocket.joinGroup(groupAddress, networkInterface);
362
363        msg = "Hello World - Different Group";
364        InetSocketAddress group2Address =
365                new InetSocketAddress(group2, receivingSocket.getLocalPort());
366        sdp = createSendDatagramPacket(group2Address, msg);
367        sendingSocket.send(sdp);
368
369        rdp = createReceiveDatagramPacket();
370        try {
371            receivingSocket.receive(rdp);
372            fail("Expected timeout");
373        } catch (SocketTimeoutException expected) {
374        }
375
376        receivingSocket.close();
377        sendingSocket.close();
378    }
379
380    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface() throws Exception {
381        if (!supportsMulticast) {
382            return;
383        }
384        // Check that we can join on specific interfaces and that we only receive if data is
385        // received on that interface. This test is only really useful on devices with multiple
386        // non-loopback interfaces.
387
388        List<NetworkInterface> realInterfaces = new ArrayList<NetworkInterface>();
389        Enumeration<NetworkInterface> theInterfaces = NetworkInterface.getNetworkInterfaces();
390        while (theInterfaces.hasMoreElements()) {
391            NetworkInterface thisInterface = theInterfaces.nextElement();
392            // Skip interfaces that do not support multicast - there's no point in proving
393            // they cannot send / receive multicast messages.
394            if (willWorkForMulticast(thisInterface)) {
395                realInterfaces.add(thisInterface);
396            }
397        }
398
399        for (NetworkInterface thisInterface : realInterfaces) {
400            // Find a suitable group IP and interface to use to sent packets to thisInterface.
401            Enumeration<InetAddress> addresses = thisInterface.getInetAddresses();
402
403            NetworkInterface sendingInterface = null;
404            InetAddress group = null;
405            if (addresses.hasMoreElements()) {
406                InetAddress firstAddress = addresses.nextElement();
407                if (firstAddress instanceof Inet4Address) {
408                    group = GOOD_IPv4;
409                    sendingInterface = ipv4NetworkInterface;
410                } else {
411                    // if this interface only seems to support IPV6 addresses
412                    group = GOOD_IPv6;
413                    sendingInterface = ipv6NetworkInterface;
414                }
415            }
416
417            // Create a receivingSocket which is joined to the group and has only asked for packets
418            // on thisInterface.
419            MulticastSocket receivingSocket = createReceivingSocket(0);
420            InetSocketAddress groupAddress =
421                    new InetSocketAddress(group, receivingSocket.getLocalPort());
422            receivingSocket.joinGroup(groupAddress, thisInterface);
423
424            // Now send out a packet on sendingInterface. We should only see the packet if we send
425            // it on thisInterface.
426            MulticastSocket sendingSocket = new MulticastSocket(0);
427            sendingSocket.setNetworkInterface(sendingInterface);
428            String msg = "Hello World - Again " + thisInterface.getName();
429            DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
430            sendingSocket.send(sdp);
431
432            DatagramPacket rdp = createReceiveDatagramPacket();
433            try {
434                receivingSocket.receive(rdp);
435
436                // If the packet is received....
437                assertEquals(thisInterface, sendingInterface);
438                assertEquals("Group member did not recv data when bound on specific interface",
439                        msg, extractMessage(rdp));
440            } catch (SocketTimeoutException e) {
441                // If the packet was not received...
442                assertTrue(!thisInterface.equals(sendingInterface));
443            }
444
445            receivingSocket.close();
446            sendingSocket.close();
447        }
448    }
449
450    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4()
451            throws Exception {
452        if (!supportsMulticast) {
453            return;
454        }
455        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
456                ipv4NetworkInterface, GOOD_IPv4);
457    }
458
459    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6()
460            throws Exception {
461        if (!supportsMulticast) {
462            return;
463        }
464        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
465                ipv6NetworkInterface, GOOD_IPv6);
466    }
467
468    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
469            NetworkInterface networkInterface, InetAddress group) throws Exception {
470        // Validate that we can join the same address on two different interfaces but not on the
471        // same interface.
472        MulticastSocket mss = new MulticastSocket(0);
473        SocketAddress groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
474        mss.joinGroup(groupSockAddr, networkInterface);
475        mss.joinGroup(groupSockAddr, loopbackInterface);
476        try {
477            mss.joinGroup(groupSockAddr, networkInterface);
478            fail("Did not get expected exception when joining for second time on same interface");
479        } catch (IOException e) {
480        }
481        mss.close();
482    }
483
484    public void test_leaveGroupLjava_net_InetAddress_IPv4() throws Exception {
485        if (!supportsMulticast) {
486            return;
487        }
488        test_leaveGroupLjava_net_InetAddress(GOOD_IPv4);
489    }
490
491    public void test_leaveGroupLjava_net_InetAddress_IPv6() throws Exception {
492        if (!supportsMulticast) {
493            return;
494        }
495        test_leaveGroupLjava_net_InetAddress(GOOD_IPv6);
496    }
497
498    private void test_leaveGroupLjava_net_InetAddress(InetAddress group) throws Exception {
499        String msg = "Hello World";
500        MulticastSocket mss = new MulticastSocket(0);
501        InetSocketAddress groupAddress = new InetSocketAddress(group, mss.getLocalPort());
502        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
503        mss.send(sdp, (byte) 10 /* ttl */);
504        try {
505            // Try to leave a group we didn't join.
506            mss.leaveGroup(group);
507            fail();
508        } catch (IOException expected) {
509        }
510        mss.close();
511    }
512
513    public void test_leaveGroup_null_null() throws Exception {
514        if (!supportsMulticast) {
515            return;
516        }
517        MulticastSocket mss = new MulticastSocket(0);
518        try {
519            mss.leaveGroup(null, null);
520            fail();
521        } catch (IllegalArgumentException expected) {
522        }
523        mss.close();
524    }
525
526    public void test_leaveGroup_non_multicast_address_IPv4() throws Exception {
527        if (!supportsMulticast) {
528            return;
529        }
530        MulticastSocket mss = new MulticastSocket(0);
531        try {
532            mss.leaveGroup(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0), null);
533            fail();
534        } catch (IOException expected) {
535        }
536        mss.close();
537    }
538
539    public void test_leaveGroup_non_multicast_address_IPv6() throws Exception {
540        if (!supportsMulticast) {
541            return;
542        }
543        MulticastSocket mss = new MulticastSocket(0);
544        try {
545            mss.leaveGroup(new InetSocketAddress(InetAddress.getByName("::1"), 0), null);
546            fail();
547        } catch (IOException expected) {
548        }
549        mss.close();
550    }
551
552    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
553            throws Exception {
554        if (!supportsMulticast) {
555            return;
556        }
557        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
558                ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
559    }
560
561    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
562            throws Exception {
563        if (!supportsMulticast) {
564            return;
565        }
566        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
567                ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
568    }
569
570    private void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
571            NetworkInterface networkInterface, InetAddress group, InetAddress group2)
572            throws Exception {
573        SocketAddress groupSockAddr = null;
574        SocketAddress groupSockAddr2 = null;
575
576        MulticastSocket mss = new MulticastSocket(0);
577        groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
578        mss.joinGroup(groupSockAddr, null);
579        mss.leaveGroup(groupSockAddr, null);
580        try {
581            mss.leaveGroup(groupSockAddr, null);
582            fail("Did not get exception when trying to leave group that was already left");
583        } catch (IOException expected) {
584        }
585
586        groupSockAddr2 = new InetSocketAddress(group2, mss.getLocalPort());
587        mss.joinGroup(groupSockAddr, networkInterface);
588        try {
589            mss.leaveGroup(groupSockAddr2, networkInterface);
590            fail("Did not get exception when trying to leave group that was never joined");
591        } catch (IOException expected) {
592        }
593
594        mss.leaveGroup(groupSockAddr, networkInterface);
595
596        mss.joinGroup(groupSockAddr, networkInterface);
597        try {
598            mss.leaveGroup(groupSockAddr, loopbackInterface);
599            fail("Did not get exception when trying to leave group on wrong interface " +
600                    "joined on [" + networkInterface + "] left on [" + loopbackInterface + "]");
601        } catch (IOException expected) {
602        }
603    }
604
605    public void test_sendLjava_net_DatagramPacketB_IPv4() throws Exception {
606        if (!supportsMulticast) {
607            return;
608        }
609        test_sendLjava_net_DatagramPacketB(GOOD_IPv4);
610    }
611
612    public void test_sendLjava_net_DatagramPacketB_IPv6() throws Exception {
613        if (!supportsMulticast) {
614            return;
615        }
616        test_sendLjava_net_DatagramPacketB(GOOD_IPv6);
617    }
618
619    private void test_sendLjava_net_DatagramPacketB(InetAddress group) throws Exception {
620        String msg = "Hello World";
621        MulticastSocket sendingSocket = new MulticastSocket(0);
622        MulticastSocket receivingSocket = createReceivingSocket(sendingSocket.getLocalPort());
623        receivingSocket.joinGroup(group);
624
625        InetSocketAddress groupAddress = new InetSocketAddress(group, sendingSocket.getLocalPort());
626        DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
627        sendingSocket.send(sdp, (byte) 10 /* ttl */);
628        sendingSocket.close();
629
630        DatagramPacket rdp = createReceiveDatagramPacket();
631        receivingSocket.receive(rdp);
632        String receivedMessage = extractMessage(rdp);
633        assertEquals("Failed to send data. Received " + rdp.getLength(), msg, receivedMessage);
634        receivingSocket.close();
635    }
636
637    public void test_setInterfaceLjava_net_InetAddress() throws Exception {
638        if (!supportsMulticast) {
639            return;
640        }
641        MulticastSocket mss = new MulticastSocket();
642        mss.setInterface(InetAddress.getLocalHost());
643        InetAddress theInterface = mss.getInterface();
644        // Under IPV6 we are not guaranteed to get the same address back as the address that was
645        // set, all we should be guaranteed is that we get an address on the same interface.
646        if (theInterface instanceof Inet6Address) {
647            assertEquals("Failed to return correct interface IPV6",
648                    NetworkInterface.getByInetAddress(mss.getInterface()),
649                    NetworkInterface.getByInetAddress(theInterface));
650        } else {
651            assertTrue("Failed to return correct interface IPV4 got:" + mss.getInterface() +
652                    " expected: " + InetAddress.getLocalHost(),
653                    mss.getInterface().equals(InetAddress.getLocalHost()));
654        }
655        mss.close();
656    }
657
658    public void test_setInterface_unbound_address_IPv4() throws Exception {
659        if (!supportsMulticast) {
660            return;
661        }
662        test_setInterface_unbound_address(GOOD_IPv4);
663    }
664
665    public void test_setInterface_unbound_address_IPv6() throws Exception {
666        if (!supportsMulticast) {
667            return;
668        }
669        test_setInterface_unbound_address(GOOD_IPv6);
670    }
671
672    // Regression test for Harmony-2410.
673    private void test_setInterface_unbound_address(InetAddress address) throws Exception {
674        MulticastSocket mss = new MulticastSocket();
675        try {
676            mss.setInterface(address);
677            fail();
678        } catch (SocketException expected) {
679        }
680        mss.close();
681    }
682
683    public void test_setNetworkInterfaceLjava_net_NetworkInterface_null() throws Exception {
684        if (!supportsMulticast) {
685            return;
686        }
687        // Validate that null interface is handled ok.
688        MulticastSocket mss = new MulticastSocket();
689        try {
690            mss.setNetworkInterface(null);
691            fail("No socket exception when we set then network interface with NULL");
692        } catch (SocketException ex) {
693        }
694        mss.close();
695    }
696
697    public void test_setNetworkInterfaceLjava_net_NetworkInterface_round_trip() throws Exception {
698        if (!supportsMulticast) {
699            return;
700        }
701        // Validate that we can get and set the interface.
702        MulticastSocket mss = new MulticastSocket();
703        mss.setNetworkInterface(ipv4NetworkInterface);
704        assertEquals("Interface did not seem to be set by setNeworkInterface",
705                ipv4NetworkInterface, mss.getNetworkInterface());
706        mss.close();
707    }
708
709    public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv4() throws Exception {
710        if (!supportsMulticast) {
711            return;
712        }
713        test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv4);
714    }
715
716    public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv6() throws Exception {
717        if (!supportsMulticast) {
718            return;
719        }
720        test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv6);
721    }
722
723    private void test_setNetworkInterfaceLjava_net_NetworkInterface(InetAddress group)
724            throws IOException, InterruptedException {
725        // Set up the receiving socket and join the group.
726        Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces();
727        while (theInterfaces.hasMoreElements()) {
728            NetworkInterface thisInterface = (NetworkInterface) theInterfaces.nextElement();
729            if (willWorkForMulticast(thisInterface)) {
730                if ((!(thisInterface.getInetAddresses().nextElement()).isLoopbackAddress())) {
731                    MulticastSocket receivingSocket = createReceivingSocket(0);
732                    InetSocketAddress groupAddress =
733                            new InetSocketAddress(group, receivingSocket.getLocalPort());
734                    receivingSocket.joinGroup(groupAddress, thisInterface);
735
736                    // Send the packets on a particular interface. The source address in the
737                    // received packet should be one of the addresses for the interface set.
738                    MulticastSocket sendingSocket = new MulticastSocket(0);
739                    sendingSocket.setNetworkInterface(thisInterface);
740                    String msg = thisInterface.getName();
741                    DatagramPacket sdp = createSendDatagramPacket(groupAddress, msg);
742                    sendingSocket.send(sdp);
743
744                    DatagramPacket rdp = createReceiveDatagramPacket();
745                    receivingSocket.receive(rdp);
746                    String receivedMessage = extractMessage(rdp);
747                    assertEquals("Group member did not recv data sent on a specific interface",
748                            msg, receivedMessage);
749                    // Stop the server.
750                    receivingSocket.close();
751                    sendingSocket.close();
752                }
753            }
754        }
755    }
756
757    public void test_setTimeToLiveI() throws Exception {
758        if (!supportsMulticast) {
759            return;
760        }
761        MulticastSocket mss = new MulticastSocket();
762        mss.setTimeToLive(120);
763        assertEquals("Returned incorrect 1st TTL", 120, mss.getTimeToLive());
764        mss.setTimeToLive(220);
765        assertEquals("Returned incorrect 2nd TTL", 220, mss.getTimeToLive());
766        mss.close();
767    }
768
769    public void test_setTTLB() throws Exception {
770        if (!supportsMulticast) {
771            return;
772        }
773        MulticastSocket mss = new MulticastSocket();
774        mss.setTTL((byte) 120);
775        assertEquals("Failed to set TTL", 120, mss.getTTL());
776        mss.close();
777    }
778
779    public void test_ConstructorLjava_net_SocketAddress() throws Exception {
780        if (!supportsMulticast) {
781            return;
782        }
783        MulticastSocket ms = new MulticastSocket((SocketAddress) null);
784        assertTrue("should not be bound", !ms.isBound() && !ms.isClosed() && !ms.isConnected());
785        ms.bind(null);
786        assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
787        ms.close();
788        assertTrue("should be closed", ms.isClosed());
789
790        ms = new MulticastSocket(0);
791        assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
792        ms.close();
793        assertTrue("should be closed", ms.isClosed());
794
795        ms = new MulticastSocket(0);
796        assertTrue("should be bound", ms.isBound() && !ms.isClosed() && !ms.isConnected());
797        ms.close();
798        assertTrue("should be closed", ms.isClosed());
799
800        try {
801            new MulticastSocket(new InetSocketAddress("unresolvedname", 31415));
802            fail();
803        } catch (IOException expected) {
804        }
805
806        // Regression test for Harmony-1162.
807        InetSocketAddress addr = new InetSocketAddress("0.0.0.0", 0);
808        MulticastSocket s = new MulticastSocket(addr);
809        assertTrue(s.getReuseAddress());
810        s.close();
811    }
812
813    public void test_getLoopbackMode() throws Exception {
814        if (!supportsMulticast) {
815            return;
816        }
817        MulticastSocket ms = new MulticastSocket(null);
818        assertTrue("should not be bound", !ms.isBound() && !ms.isClosed() && !ms.isConnected());
819        ms.getLoopbackMode();
820        assertTrue("should not be bound", !ms.isBound() && !ms.isClosed() && !ms.isConnected());
821        ms.close();
822        assertTrue("should be closed", ms.isClosed());
823    }
824
825    public void test_setLoopbackModeZ() throws Exception {
826        if (!supportsMulticast) {
827            return;
828        }
829        MulticastSocket ms = new MulticastSocket();
830        ms.setLoopbackMode(true);
831        assertTrue("loopback should be true", ms.getLoopbackMode());
832        ms.setLoopbackMode(false);
833        assertTrue("loopback should be false", !ms.getLoopbackMode());
834        ms.close();
835        assertTrue("should be closed", ms.isClosed());
836    }
837
838    public void test_setLoopbackModeSendReceive_IPv4() throws Exception {
839        if (!supportsMulticast) {
840            return;
841        }
842        test_setLoopbackModeSendReceive(GOOD_IPv4);
843    }
844
845    public void test_setLoopbackModeSendReceive_IPv6() throws Exception {
846        if (!supportsMulticast) {
847            return;
848        }
849        test_setLoopbackModeSendReceive(GOOD_IPv6);
850    }
851
852    private void test_setLoopbackModeSendReceive(InetAddress group) throws IOException {
853        // Test send receive.
854        final String message = "Hello, world!";
855
856        MulticastSocket socket = new MulticastSocket(0);
857        socket.setLoopbackMode(false); // false indicates doing loop back
858        socket.joinGroup(group);
859
860        // Send the datagram.
861        InetSocketAddress groupAddress = new InetSocketAddress(group, socket.getLocalPort());
862        DatagramPacket sendDatagram = createSendDatagramPacket(groupAddress, message);
863        socket.send(sendDatagram);
864
865        // Receive the datagram.
866        DatagramPacket recvDatagram = createReceiveDatagramPacket();
867        socket.setSoTimeout(5000); // Prevent eternal block in.
868        socket.receive(recvDatagram);
869        String recvMessage = extractMessage(recvDatagram);
870        assertEquals(message, recvMessage);
871        socket.close();
872    }
873
874    public void test_setReuseAddressZ() throws Exception {
875        if (!supportsMulticast) {
876            return;
877        }
878        // Test case were we to set ReuseAddress to false.
879        MulticastSocket theSocket1 = new MulticastSocket(null);
880        theSocket1.setReuseAddress(false);
881
882        MulticastSocket theSocket2 = new MulticastSocket(null);
883        theSocket2.setReuseAddress(false);
884
885        InetSocketAddress addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
886        theSocket1.bind(addr);
887        addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
888        try {
889            theSocket2.bind(addr);
890            fail("No exception when trying to connect to do duplicate socket bind with re-useaddr"
891                    + " set to false");
892        } catch (BindException expected) {
893        }
894        theSocket1.close();
895        theSocket2.close();
896
897        // Test case were we set it to true.
898        theSocket1 = new MulticastSocket(null);
899        theSocket2 = new MulticastSocket(null);
900        theSocket1.setReuseAddress(true);
901        theSocket2.setReuseAddress(true);
902        addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
903        theSocket1.bind(addr);
904        addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
905        theSocket2.bind(addr);
906
907        theSocket1.close();
908        theSocket2.close();
909
910        // Test the default case which we expect to be the same on all platforms.
911        theSocket1 = new MulticastSocket(null);
912        theSocket2 = new MulticastSocket(null);
913        addr = new InetSocketAddress(Inet4Address.getLocalHost(), 0);
914        theSocket1.bind(addr);
915        addr = new InetSocketAddress(Inet4Address.getLocalHost(), theSocket1.getLocalPort());
916        theSocket2.bind(addr);
917        theSocket1.close();
918        theSocket2.close();
919    }
920
921    private static boolean willWorkForMulticast(NetworkInterface iface) throws IOException {
922        return iface.isUp()
923                // Typically loopback interfaces do not support multicast, but we rule them out
924                // explicitly anyway.
925                && !iface.isLoopback()
926                // Point-to-point interfaces are known to cause problems. http://b/23279677
927                && !iface.isPointToPoint()
928                && iface.supportsMulticast()
929                && iface.getInetAddresses().hasMoreElements();
930    }
931
932    private static MulticastSocket createReceivingSocket(int aPort) throws IOException {
933        MulticastSocket ms = new MulticastSocket(aPort);
934        ms.setSoTimeout(2000);
935        return ms;
936    }
937
938    private static DatagramPacket createReceiveDatagramPacket() {
939        byte[] rbuf = new byte[512];
940        return new DatagramPacket(rbuf, rbuf.length);
941    }
942
943    private static DatagramPacket createSendDatagramPacket(
944            InetSocketAddress groupAndPort, String msg) {
945        return new DatagramPacket(
946                msg.getBytes(), msg.length(), groupAndPort.getAddress(), groupAndPort.getPort());
947    }
948
949    private static String extractMessage(DatagramPacket rdp) {
950        return new String(rdp.getData(), 0, rdp.getLength());
951    }
952}
953