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