/*
* Copyright (c) 2007, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import sun.net.ext.ExtendedSocketOptions;
/**
* This class defines the plain DatagramSocketImpl that is used on
* Windows platforms greater than or equal to Windows Vista. These
* platforms have a dual layer TCP/IP stack and can handle both IPv4
* and IPV6 through a single file descriptor.
* <p>
* Note: Multicasting on a dual layer TCP/IP stack is always done with
* TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
* of behavior defined for multicasting over a dual layer socket by the RFC.
*
* @author Chris Hegarty
*/
class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
static {
initIDs();
}
// true if this socket is exclusively bound
private final boolean exclusiveBind;
/*
* Set to true if SO_REUSEADDR is set after the socket is bound to
* indicate SO_REUSEADDR is being emulated
*/
private boolean reuseAddressEmulated;
// emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
private boolean isReuseAddress;
DualStackPlainDatagramSocketImpl(boolean exclBind) {
super(false);
exclusiveBind = exclBind;
}
protected void datagramSocketCreate() throws SocketException {
if (fd == null)
throw new SocketException("Socket closed");
int newfd = socketCreate();
fdAccess.set(fd, newfd);
}
protected synchronized void bind0(int lport, InetAddress laddr)
throws SocketException {
int nativefd = checkAndReturnNativeFD();
if (laddr == null)
throw new NullPointerException("argument address");
socketBind(nativefd, laddr, lport, exclusiveBind);
if (lport == 0) {
localPort = socketLocalPort(nativefd);
} else {
localPort = lport;
}
}
protected synchronized int peek(InetAddress address) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("Null address in peek()");
// Use peekData()
DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
int peekPort = peekData(peekPacket);
address = peekPacket.getAddress();
return peekPort;
}
protected synchronized int peekData(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("packet");
if (p.getData() == null)
throw new NullPointerException("packet buffer");
return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/);
}
protected synchronized void receive0(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("packet");
if (p.getData() == null)
throw new NullPointerException("packet buffer");
socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/);
}
protected void send0(DatagramPacket p) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (p == null)
throw new NullPointerException("null packet");
if (p.getAddress() == null ||p.getData() ==null)
throw new NullPointerException("null address || null buffer");
socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(),
p.getAddress(), p.getPort(), connected);
}
protected void connect0(InetAddress address, int port) throws SocketException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("address");
socketConnect(nativefd, address, port);
}
protected void disconnect0(int family /*unused*/) {
if (fd == null || !fd.valid())
return; // disconnect doesn't throw any exceptions
socketDisconnect(fdAccess.get(fd));
}
protected void datagramSocketClose() {
if (fd == null || !fd.valid())
return; // close doesn't throw any exceptions
socketClose(fdAccess.get(fd));
fdAccess.set(fd, -1);
}
@SuppressWarnings("fallthrough")
protected void socketSetOption(int opt, Object val) throws SocketException {
int nativefd = checkAndReturnNativeFD();
int optionValue = 0;
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT) {
throw new UnsupportedOperationException("unsupported option");
}
switch(opt) {
case IP_TOS :
case SO_RCVBUF :
case SO_SNDBUF :
optionValue = ((Integer)val).intValue();
break;
case SO_REUSEADDR :
if (exclusiveBind && localPort != 0) {
// socket already bound, emulate SO_REUSEADDR
reuseAddressEmulated = true;
isReuseAddress = (Boolean)val;
return;
}
//Intentional fallthrough
case SO_BROADCAST :
optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
break;
default: /* shouldn't get here */
throw new SocketException("Option not supported");
}
socketSetIntOption(nativefd, opt, optionValue);
}
protected Object socketGetOption(int opt) throws SocketException {
int nativefd = checkAndReturnNativeFD();
// SO_BINDADDR is not a socket option.
if (opt == SO_BINDADDR) {
return socketLocalAddress(nativefd);
}
if (opt == SO_REUSEADDR && reuseAddressEmulated)
return isReuseAddress;
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT)
throw new UnsupportedOperationException("unsupported option");
int value = socketGetIntOption(nativefd, opt);
Object returnValue = null;
switch (opt) {
case SO_REUSEADDR :
case SO_BROADCAST :
returnValue = (value == 0) ? Boolean.FALSE : Boolean.TRUE;
break;
case IP_TOS :
case SO_RCVBUF :
case SO_SNDBUF :
returnValue = Integer.valueOf(value);
break;
default: /* shouldn't get here */
throw new SocketException("Option not supported");
}
return returnValue;
}
@Override
protected Set<SocketOption<?>> supportedOptions() {
HashSet<SocketOption<?>> options = new HashSet<>();
options.add(StandardSocketOptions.SO_SNDBUF);
options.add(StandardSocketOptions.SO_RCVBUF);
options.add(StandardSocketOptions.SO_REUSEADDR);
options.add(StandardSocketOptions.SO_BROADCAST);
options.add(StandardSocketOptions.IP_TOS);
options.addAll(ExtendedSocketOptions.datagramSocketOptions());
return Collections.unmodifiableSet(options);
}
/* Multicast specific methods.
* Multicasting on a dual layer TCP/IP stack is always done with
* TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
* of behavior defined for multicasting over a dual layer socket by the RFC.
*/
protected void join(InetAddress inetaddr, NetworkInterface netIf)
throws IOException {
throw new IOException("Method not implemented!");
}
protected void leave(InetAddress inetaddr, NetworkInterface netIf)
throws IOException {
throw new IOException("Method not implemented!");
}
protected void setTimeToLive(int ttl) throws IOException {
throw new IOException("Method not implemented!");
}
protected int getTimeToLive() throws IOException {
throw new IOException("Method not implemented!");
}
@Deprecated
protected void setTTL(byte ttl) throws IOException {
throw new IOException("Method not implemented!");
}
@Deprecated
protected byte getTTL() throws IOException {
throw new IOException("Method not implemented!");
}
/* END Multicast specific methods */
private int checkAndReturnNativeFD() throws SocketException {
if (fd == null || !fd.valid())
throw new SocketException("Socket closed");
return fdAccess.get(fd);
}
/* Native methods */
private static native void initIDs();
/**代码未完, 请加载全部代码(NowJava.com).**/