--- old/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java 2019-05-27 11:33:53.893804714 +0100 +++ new/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java 2019-05-27 11:33:53.381804732 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,11 @@ import java.io.IOException; import java.util.Collections; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import sun.net.ResourceManager; +import sun.net.ext.ExtendedSocketOptions; import sun.security.action.GetPropertyAction; /** @@ -88,26 +90,6 @@ } /** - * Returns a set of SocketOptions supported by this impl and by this impl's - * socket (Socket or ServerSocket) - * - * @return a Set of SocketOptions - */ - @Override - protected Set> supportedOptions() { - Set> options; - if (isReusePortAvailable()) { - options = new HashSet<>(); - options.addAll(super.supportedOptions()); - options.add(StandardSocketOptions.SO_REUSEPORT); - options = Collections.unmodifiableSet(options); - } else { - options = super.supportedOptions(); - } - return options; - } - - /** * Creates a datagram socket */ protected synchronized void create() throws SocketException { @@ -400,6 +382,125 @@ return result; } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + + private static final Set> datagramSocketOptions = datagramSocketOptions(); + private static final Set> multicastSocketOptions = multicastSocketOptions(); + + private static Set> datagramSocketOptions() { + HashSet> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.IP_TOS); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.datagramSocketOptions()); + return Collections.unmodifiableSet(options); + } + + private static Set> multicastSocketOptions() { + HashSet> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.IP_TOS); + options.add(StandardSocketOptions.IP_MULTICAST_IF); + options.add(StandardSocketOptions.IP_MULTICAST_TTL); + options.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.datagramSocketOptions()); + return Collections.unmodifiableSet(options); + } + + @Override + protected Set> supportedOptions() { + if (getDatagramSocket() instanceof MulticastSocket) + return multicastSocketOptions; + else + return datagramSocketOptions; + } + + @Override + protected void setOption(SocketOption name, T value) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); + + if (isClosed()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_SNDBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid send buffer size:" + value); + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid recv buffer size:" + value); + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + setOption(SocketOptions.SO_REUSEPORT, value); + } else if (name == StandardSocketOptions.IP_TOS) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid IP_TOS value: " + value); + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF ) { + setOption(SocketOptions.IP_MULTICAST_IF2, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid TTL/hop value: " + value); + setTimeToLive((Integer)value); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP) { + setOption(SocketOptions.IP_MULTICAST_LOOP, value); + } else if (extendedOptions.isOptionSupported(name)) { + extendedOptions.setOption(fd, name, value); + } else { + throw new AssertionError("unknown option :" + name); + } + } + + @Override + @SuppressWarnings("unchecked") + protected T getOption(SocketOption name) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (isClosed()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_SNDBUF) { + return (T) getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T) getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + return (T) getOption(SocketOptions.SO_REUSEPORT); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T) getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF) { + return (T) getOption(SocketOptions.IP_MULTICAST_IF2); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL) { + return (T) ((Integer) getTimeToLive()); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP) { + return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); + } else if (extendedOptions.isOptionSupported(name)) { + return (T) extendedOptions.getOption(fd, name); + } else { + throw new AssertionError("unknown option: " + name); + } + } + protected abstract void datagramSocketCreate() throws SocketException; protected abstract void datagramSocketClose(); protected abstract void socketSetOption(int opt, Object val)