Path: blob/master/test/jdk/java/net/MulticastSocket/SetLoopbackOption.java
41149 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 823329626* @summary Check that MulticastSocket::setOption and MulticastSocket::getOption27* return the correct result for StandardSocketOptions.IP_MULTICAST_LOOP.28* The test sets a DatagramSocketImplFactory and needs to run in /othervm29* mode.30* @run testng/othervm SetLoopbackOption31* @run testng/othervm -Djava.net.preferIPv4Stack=true SetLoopbackOption32* @run testng/othervm -Djava.net.preferIPv6Addresses=true SetLoopbackOption33* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SetLoopbackOption34*/3536import java.io.FileDescriptor;37import java.io.IOException;38import java.net.DatagramPacket;39import java.net.DatagramSocket;40import java.net.DatagramSocketImpl;41import java.net.DatagramSocketImplFactory;42import java.net.InetAddress;43import java.net.InetSocketAddress;44import java.net.MulticastSocket;45import java.net.NetworkInterface;46import java.net.SocketAddress;47import java.net.SocketException;48import java.net.SocketOption;49import java.net.SocketOptions;50import java.net.StandardSocketOptions;51import java.util.HashMap;52import java.util.Map;53import java.util.Set;5455import org.testng.annotations.Test;56import static org.testng.Assert.*;5758import static java.lang.System.out;5960public class SetLoopbackOption {6162final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();6364@Test65public void run() throws Exception {66var bindAddress = new InetSocketAddress(loopbackAddress, 0);67try (MulticastSocket sock = new MulticastSocket(null)) {68out.println("Testing unbound socket");69test(sock, null);70out.printf("\nBinding socket to %s and testing again%n", bindAddress);71sock.bind(bindAddress);72test(sock, null);73}74TestDatagramSocketImplFactory factory = new TestDatagramSocketImplFactory();75DatagramSocket.setDatagramSocketImplFactory(factory);76try (MulticastSocket sock = new MulticastSocket(null)) {77out.println("\nTesting unbound socket with custom impl");78TestDatagramSocketImpl impl = factory.last;79test(sock, impl);80out.printf("\nBinding socket to %s and testing again%n", bindAddress);81sock.bind(new InetSocketAddress(loopbackAddress, 0));82test(sock, impl);83}84}8586private void test(MulticastSocket sock, TestDatagramSocketImpl impl) throws Exception {87out.println("Testing with " + sock.getClass() + (impl == null ? "" : ", " + impl.getClass()));88var op = StandardSocketOptions.IP_MULTICAST_LOOP;89var opId = SocketOptions.IP_MULTICAST_LOOP;90boolean enable = sock.getOption(op);91assertTrue(enable, "Initial Value for " + op);92boolean disable = sock.getLoopbackMode();93assertFalse(disable, "Initial Value for getLoopbackMode()");94if (impl != null) {95assertFalse((Boolean)impl.getOption(opId));96assertTrue((Boolean)impl.getOption(op));97}9899out.println("Setting " + op + " to " + false);100if (impl != null) {101// allows setOption(SocketOption, Object) to be called102impl.allowAllSetOptions(true);103}104sock.setOption(op, false);105enable = sock.getOption(op);106assertFalse(enable, "Value for " + op);107disable = sock.getLoopbackMode();108assertTrue(disable, "Value for getLoopbackMode()");109if (impl != null) {110assertTrue((Boolean)impl.getOption(opId));111assertFalse((Boolean)impl.getOption(op));112}113out.println("Setting " + op + " to " + true);114sock.setOption(op, true);115enable = sock.getOption(op);116assertTrue(enable, "Value for " + op);117disable = sock.getLoopbackMode();118assertFalse(disable, "Value for getLoopbackMode()");119if (impl != null) {120assertFalse((Boolean)impl.getOption(opId));121assertTrue((Boolean)impl.getOption(op));122}123124out.println("Calling setLoopbackMode(true)");125if (impl != null) {126// for backward compatibility reason, setLoopbackMode127// should call setOption(int, Object), not setOption(SocketOption, Object)128// Make sure that an exception is thrown if the latter is ever called.129impl.allowAllSetOptions(false);130}131sock.setLoopbackMode(true);132enable = sock.getOption(op);133assertFalse(enable, "Value for " + op);134disable = sock.getLoopbackMode();135assertTrue(disable, "Value for getLoopbackMode()");136if (impl != null) {137assertTrue((Boolean)impl.getOption(opId));138assertFalse((Boolean)impl.getOption(op));139}140out.println("Calling setLoopbackMode(false)");141sock.setLoopbackMode(false);142enable = sock.getOption(op);143assertTrue(enable, "Value for " + op);144disable = sock.getLoopbackMode();145assertFalse(disable, "Value for getLoopbackMode()");146if (impl != null) {147assertFalse((Boolean)impl.getOption(opId));148assertTrue((Boolean)impl.getOption(op));149}150}151152// Used to attempt to control what is called/passed to the impl.153static class TestDatagramSocketImplFactory implements DatagramSocketImplFactory {154TestDatagramSocketImpl last;155public synchronized DatagramSocketImpl createDatagramSocketImpl() {156TestDatagramSocketImpl last = this.last;157if (last == null) {158return (last = this.last = new TestDatagramSocketImpl());159} else {160throw new AssertionError("Only one instance should be created");161}162}163}164165// Used to attempt to control what is called/passed to the impl.166static class TestDatagramSocketImpl extends DatagramSocketImpl {167InetAddress address;168private boolean allowAllSetOptions;169170@Override171protected void create() throws SocketException {172legacyOptions.put(SocketOptions.IP_MULTICAST_LOOP, false);173options.put(StandardSocketOptions.IP_MULTICAST_LOOP, true);174}175176final Map<Integer, Object> legacyOptions = new HashMap<>();177final Map<SocketOption<?>, Object> options = new HashMap<>();178179static <T> T shouldNotComeHere() {180throw new AssertionError("should not come here");181}182183@Override184protected void bind(int lport, InetAddress laddr) throws SocketException {185this.localPort = (lport == 0 ? 6789 : lport);186this.address = laddr;187}188189@Override190protected void send(DatagramPacket p) throws IOException {191shouldNotComeHere();192}193194@Override195protected int peek(InetAddress i) throws IOException {196return shouldNotComeHere();197}198199@Override200protected int peekData(DatagramPacket p) throws IOException {201return shouldNotComeHere();202}203204@Override205protected void receive(DatagramPacket p) throws IOException {206shouldNotComeHere();207}208209@Override210protected void setTTL(byte ttl) throws IOException {211shouldNotComeHere();212}213214@Override215protected byte getTTL() throws IOException {216return shouldNotComeHere();217}218219@Override220protected void setTimeToLive(int ttl) throws IOException {221shouldNotComeHere();222}223224@Override225protected int getTimeToLive() throws IOException {226return shouldNotComeHere();227}228229@Override230protected void join(InetAddress inetaddr) throws IOException {231shouldNotComeHere();232}233234@Override235protected void leave(InetAddress inetaddr) throws IOException {236shouldNotComeHere();237}238239@Override240protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)241throws IOException {242shouldNotComeHere();243}244245@Override246protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)247throws IOException {248shouldNotComeHere();249}250251@Override252protected void close() {253254}255256@Override257public void setOption(int optID, Object value) throws SocketException {258legacyOptions.put(optID, value);259if (optID == SocketOptions.IP_MULTICAST_LOOP) {260boolean disable = (Boolean) value;261options.put(StandardSocketOptions.IP_MULTICAST_LOOP, !disable);262}263}264265@Override266public Object getOption(int optID) throws SocketException {267return legacyOptions.get(optID);268}269270@Override271protected Set<SocketOption<?>> supportedOptions() {272return Set.of(StandardSocketOptions.IP_MULTICAST_LOOP);273}274275@Override276protected void connect(InetAddress address, int port) throws SocketException {277shouldNotComeHere();278}279280@Override281protected void disconnect() {282shouldNotComeHere();283}284285@Override286protected FileDescriptor getFileDescriptor() {287return super.getFileDescriptor();288}289290@Override291protected <T> void setOption(SocketOption<T> name, T value) throws IOException {292if (!allowAllSetOptions) shouldNotComeHere();293options.put(name, value);294if (name.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) {295boolean enable = (Boolean)value;296legacyOptions.put(SocketOptions.IP_MULTICAST_LOOP, !enable);297}298}299300@Override301protected <T> T getOption(SocketOption<T> name) throws IOException {302return (T) options.get(name);303}304305public void allowAllSetOptions(boolean allow) {306this.allowAllSetOptions = allow;307}308}309310public static void main (String args[]) throws Exception {311new SetLoopbackOption().run();312}313}314315316