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