8201510: Merge TwoStacksPlainSocketImpl into DualStackPlainSocketImpl [win]
Reviewed-by: chegar
This commit is contained in:
parent
e81b41a371
commit
9303a8a180
@ -26,14 +26,18 @@ package java.net;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import sun.security.action.GetPropertyAction;
|
||||||
import jdk.internal.misc.SharedSecrets;
|
import jdk.internal.misc.SharedSecrets;
|
||||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class defines the plain SocketImpl that is used on Windows platforms
|
* This class defines the plain SocketImpl.
|
||||||
* greater or equal to Windows Vista. These platforms have a dual
|
* When java.net.preferIPv4Stack system property is set to true, it uses
|
||||||
* layer TCP/IP stack and can handle both IPv4 and IPV6 through a
|
* IPv4-only socket.
|
||||||
* single file descriptor.
|
* When java.net.preferIPv4Stack is set to false, it handles both IPv4
|
||||||
|
* and IPv6 through a single file descriptor.
|
||||||
*
|
*
|
||||||
* @author Chris Hegarty
|
* @author Chris Hegarty
|
||||||
*/
|
*/
|
||||||
@ -43,30 +47,43 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
private static final JavaIOFileDescriptorAccess fdAccess =
|
||||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||||
|
|
||||||
// true if this socket is exclusively bound
|
private static final boolean preferIPv4Stack =
|
||||||
private final boolean exclusiveBind;
|
Boolean.parseBoolean(AccessController.doPrivileged(
|
||||||
|
new GetPropertyAction("java.net.preferIPv4Stack", "false")));
|
||||||
|
|
||||||
// emulates SO_REUSEADDR when exclusiveBind is true
|
/**
|
||||||
|
* Empty value of sun.net.useExclusiveBind is treated as 'true'.
|
||||||
|
*/
|
||||||
|
private static final boolean useExclusiveBind;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String exclBindProp = AccessController.doPrivileged(
|
||||||
|
new GetPropertyAction("sun.net.useExclusiveBind", ""));
|
||||||
|
useExclusiveBind = exclBindProp.isEmpty()
|
||||||
|
|| Boolean.parseBoolean(exclBindProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// emulates SO_REUSEADDR when useExclusiveBind is true
|
||||||
private boolean isReuseAddress;
|
private boolean isReuseAddress;
|
||||||
|
|
||||||
public DualStackPlainSocketImpl(boolean exclBind) {
|
public DualStackPlainSocketImpl() {
|
||||||
exclusiveBind = exclBind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
|
public DualStackPlainSocketImpl(FileDescriptor fd) {
|
||||||
this.fd = fd;
|
this.fd = fd;
|
||||||
exclusiveBind = exclBind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketCreate(boolean stream) throws IOException {
|
void socketCreate(boolean stream) throws IOException {
|
||||||
if (fd == null)
|
if (fd == null)
|
||||||
throw new SocketException("Socket closed");
|
throw new SocketException("Socket closed");
|
||||||
|
|
||||||
int newfd = socket0(stream, false /*v6 Only*/);
|
int newfd = socket0(stream);
|
||||||
|
|
||||||
fdAccess.set(fd, newfd);
|
fdAccess.set(fd, newfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketConnect(InetAddress address, int port, int timeout)
|
void socketConnect(InetAddress address, int port, int timeout)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
@ -74,6 +91,9 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
if (address == null)
|
if (address == null)
|
||||||
throw new NullPointerException("inet address argument is null.");
|
throw new NullPointerException("inet address argument is null.");
|
||||||
|
|
||||||
|
if (preferIPv4Stack && !(address instanceof Inet4Address))
|
||||||
|
throw new SocketException("Protocol family not supported");
|
||||||
|
|
||||||
int connectResult;
|
int connectResult;
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
connectResult = connect0(nativefd, address, port);
|
connectResult = connect0(nativefd, address, port);
|
||||||
@ -97,13 +117,17 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
localport = localPort0(nativefd);
|
localport = localPort0(nativefd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketBind(InetAddress address, int port) throws IOException {
|
void socketBind(InetAddress address, int port) throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
|
|
||||||
if (address == null)
|
if (address == null)
|
||||||
throw new NullPointerException("inet address argument is null.");
|
throw new NullPointerException("inet address argument is null.");
|
||||||
|
|
||||||
bind0(nativefd, address, port, exclusiveBind);
|
if (preferIPv4Stack && !(address instanceof Inet4Address))
|
||||||
|
throw new SocketException("Protocol family not supported");
|
||||||
|
|
||||||
|
bind0(nativefd, address, port, useExclusiveBind);
|
||||||
if (port == 0) {
|
if (port == 0) {
|
||||||
localport = localPort0(nativefd);
|
localport = localPort0(nativefd);
|
||||||
} else {
|
} else {
|
||||||
@ -113,12 +137,14 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketListen(int backlog) throws IOException {
|
void socketListen(int backlog) throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
|
|
||||||
listen0(nativefd, backlog);
|
listen0(nativefd, backlog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketAccept(SocketImpl s) throws IOException {
|
void socketAccept(SocketImpl s) throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
|
|
||||||
@ -148,13 +174,17 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
s.port = isa.getPort();
|
s.port = isa.getPort();
|
||||||
s.address = isa.getAddress();
|
s.address = isa.getAddress();
|
||||||
s.localport = localport;
|
s.localport = localport;
|
||||||
|
if (preferIPv4Stack && !(s.address instanceof Inet4Address))
|
||||||
|
throw new SocketException("Protocol family not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
int socketAvailable() throws IOException {
|
int socketAvailable() throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
return available0(nativefd);
|
return available0(nativefd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
|
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
|
||||||
if (fd == null)
|
if (fd == null)
|
||||||
throw new SocketException("Socket closed");
|
throw new SocketException("Socket closed");
|
||||||
@ -167,6 +197,7 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
close0(nativefd);
|
close0(nativefd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketShutdown(int howto) throws IOException {
|
void socketShutdown(int howto) throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
shutdown0(nativefd, howto);
|
shutdown0(nativefd, howto);
|
||||||
@ -174,41 +205,51 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
|
|
||||||
// Intentional fallthrough after SO_REUSEADDR
|
// Intentional fallthrough after SO_REUSEADDR
|
||||||
@SuppressWarnings("fallthrough")
|
@SuppressWarnings("fallthrough")
|
||||||
|
@Override
|
||||||
void socketSetOption(int opt, boolean on, Object value)
|
void socketSetOption(int opt, boolean on, Object value)
|
||||||
throws SocketException {
|
throws SocketException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
if (opt == SO_TIMEOUT) { // timeout implemented through select.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
// SO_REUSEPORT is not supported on Windows.
|
||||||
if (opt == SO_REUSEPORT) {
|
if (opt == SO_REUSEPORT) {
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
throw new UnsupportedOperationException("unsupported option");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nativefd = checkAndReturnNativeFD();
|
||||||
|
|
||||||
|
if (opt == SO_TIMEOUT) {
|
||||||
|
if (preferIPv4Stack) {
|
||||||
|
// Don't enable the socket option on ServerSocket as it's
|
||||||
|
// meaningless (we don't receive on a ServerSocket).
|
||||||
|
if (serverSocket == null) {
|
||||||
|
setSoTimeout0(nativefd, ((Integer)value).intValue());
|
||||||
|
}
|
||||||
|
} // else timeout is implemented through select.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int optionValue = 0;
|
int optionValue = 0;
|
||||||
|
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case SO_REUSEADDR :
|
case SO_REUSEADDR:
|
||||||
if (exclusiveBind) {
|
if (useExclusiveBind) {
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
// SO_REUSEADDR emulated when using exclusive bind
|
||||||
isReuseAddress = on;
|
isReuseAddress = on;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// intentional fallthrough
|
// intentional fallthrough
|
||||||
case TCP_NODELAY :
|
case TCP_NODELAY:
|
||||||
case SO_OOBINLINE :
|
case SO_OOBINLINE:
|
||||||
case SO_KEEPALIVE :
|
case SO_KEEPALIVE:
|
||||||
optionValue = on ? 1 : 0;
|
optionValue = on ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case SO_SNDBUF :
|
case SO_SNDBUF:
|
||||||
case SO_RCVBUF :
|
case SO_RCVBUF:
|
||||||
case IP_TOS :
|
case IP_TOS:
|
||||||
optionValue = ((Integer)value).intValue();
|
optionValue = ((Integer)value).intValue();
|
||||||
break;
|
break;
|
||||||
case SO_LINGER :
|
case SO_LINGER:
|
||||||
if (on) {
|
if (on) {
|
||||||
optionValue = ((Integer)value).intValue();
|
optionValue = ((Integer)value).intValue();
|
||||||
} else {
|
} else {
|
||||||
optionValue = -1;
|
optionValue = -1;
|
||||||
}
|
}
|
||||||
@ -220,7 +261,15 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
setIntOption(nativefd, opt, optionValue);
|
setIntOption(nativefd, opt, optionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
|
@Override
|
||||||
|
int socketGetOption(int opt, Object iaContainerObj)
|
||||||
|
throws SocketException {
|
||||||
|
|
||||||
|
// SO_REUSEPORT is not supported on Windows.
|
||||||
|
if (opt == SO_REUSEPORT) {
|
||||||
|
throw new UnsupportedOperationException("unsupported option");
|
||||||
|
}
|
||||||
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
|
|
||||||
// SO_BINDADDR is not a socket option.
|
// SO_BINDADDR is not a socket option.
|
||||||
@ -228,27 +277,24 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
|
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
|
||||||
return 0; // return value doesn't matter.
|
return 0; // return value doesn't matter.
|
||||||
}
|
}
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
if (opt == SO_REUSEPORT) {
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
|
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
// SO_REUSEADDR emulated when using exclusive bind
|
||||||
if (opt == SO_REUSEADDR && exclusiveBind)
|
if (opt == SO_REUSEADDR && useExclusiveBind)
|
||||||
return isReuseAddress? 1 : -1;
|
return isReuseAddress ? 1 : -1;
|
||||||
|
|
||||||
int value = getIntOption(nativefd, opt);
|
int value = getIntOption(nativefd, opt);
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case TCP_NODELAY :
|
case TCP_NODELAY:
|
||||||
case SO_OOBINLINE :
|
case SO_OOBINLINE:
|
||||||
case SO_KEEPALIVE :
|
case SO_KEEPALIVE:
|
||||||
case SO_REUSEADDR :
|
case SO_REUSEADDR:
|
||||||
return (value == 0) ? -1 : 1;
|
return (value == 0) ? -1 : 1;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void socketSendUrgentData(int data) throws IOException {
|
void socketSendUrgentData(int data) throws IOException {
|
||||||
int nativefd = checkAndReturnNativeFD();
|
int nativefd = checkAndReturnNativeFD();
|
||||||
sendOOB(nativefd, data);
|
sendOOB(nativefd, data);
|
||||||
@ -271,7 +317,7 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
|
|
||||||
static native void initIDs();
|
static native void initIDs();
|
||||||
|
|
||||||
static native int socket0(boolean stream, boolean v6Only) throws IOException;
|
static native int socket0(boolean stream) throws IOException;
|
||||||
|
|
||||||
static native void bind0(int fd, InetAddress localAddress, int localport,
|
static native void bind0(int fd, InetAddress localAddress, int localport,
|
||||||
boolean exclBind)
|
boolean exclBind)
|
||||||
@ -300,6 +346,8 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
|
|
||||||
static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
|
static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
|
||||||
|
|
||||||
|
static native void setSoTimeout0(int fd, int timeout) throws SocketException;
|
||||||
|
|
||||||
static native int getIntOption(int fd, int cmd) throws SocketException;
|
static native int getIntOption(int fd, int cmd) throws SocketException;
|
||||||
|
|
||||||
static native void sendOOB(int fd, int data) throws IOException;
|
static native void sendOOB(int fd, int data) throws IOException;
|
||||||
|
@ -25,20 +25,13 @@
|
|||||||
package java.net;
|
package java.net;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import sun.security.action.GetPropertyAction;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class PlainSocketImpl simply delegates to the appropriate real
|
* This class PlainSocketImpl simply delegates to the appropriate real
|
||||||
* SocketImpl. We do this because PlainSocketImpl is already extended
|
* SocketImpl. We do this because PlainSocketImpl is already extended
|
||||||
* by SocksSocketImpl.
|
* by SocksSocketImpl.
|
||||||
* <p>
|
* <p>
|
||||||
* There are two possibilities for the real SocketImpl,
|
* There is one possibility for the real SocketImpl: DualStackPlainSocketImpl.
|
||||||
* TwoStacksPlainSocketImpl or DualStackPlainSocketImpl. We use
|
|
||||||
* DualStackPlainSocketImpl on systems that have a dual stack
|
|
||||||
* TCP implementation. Otherwise we create an instance of
|
|
||||||
* TwoStacksPlainSocketImpl and delegate to it.
|
|
||||||
*
|
*
|
||||||
* @author Chris Hegarty
|
* @author Chris Hegarty
|
||||||
*/
|
*/
|
||||||
@ -46,44 +39,18 @@ import sun.security.action.GetPropertyAction;
|
|||||||
class PlainSocketImpl extends AbstractPlainSocketImpl {
|
class PlainSocketImpl extends AbstractPlainSocketImpl {
|
||||||
private AbstractPlainSocketImpl impl;
|
private AbstractPlainSocketImpl impl;
|
||||||
|
|
||||||
/* java.net.preferIPv4Stack */
|
|
||||||
private static final boolean preferIPv4Stack;
|
|
||||||
|
|
||||||
/* True if exclusive binding is on for Windows */
|
|
||||||
private static final boolean exclusiveBind;
|
|
||||||
|
|
||||||
static {
|
|
||||||
preferIPv4Stack = Boolean.parseBoolean(
|
|
||||||
AccessController.doPrivileged(
|
|
||||||
new GetPropertyAction("java.net.preferIPv4Stack")));
|
|
||||||
|
|
||||||
String exclBindProp = AccessController.doPrivileged(
|
|
||||||
new GetPropertyAction("sun.net.useExclusiveBind", ""));
|
|
||||||
exclusiveBind = (exclBindProp.isEmpty())
|
|
||||||
? true
|
|
||||||
: Boolean.parseBoolean(exclBindProp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an empty instance.
|
* Constructs an empty instance.
|
||||||
*/
|
*/
|
||||||
PlainSocketImpl() {
|
PlainSocketImpl() {
|
||||||
if (!preferIPv4Stack) {
|
impl = new DualStackPlainSocketImpl();
|
||||||
impl = new DualStackPlainSocketImpl(exclusiveBind);
|
|
||||||
} else {
|
|
||||||
impl = new TwoStacksPlainSocketImpl(exclusiveBind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an instance with the given file descriptor.
|
* Constructs an instance with the given file descriptor.
|
||||||
*/
|
*/
|
||||||
PlainSocketImpl(FileDescriptor fd) {
|
PlainSocketImpl(FileDescriptor fd) {
|
||||||
if (!preferIPv4Stack) {
|
impl = new DualStackPlainSocketImpl(fd);
|
||||||
impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
|
|
||||||
} else {
|
|
||||||
impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override methods in SocketImpl that access impl's fields.
|
// Override methods in SocketImpl that access impl's fields.
|
||||||
@ -148,18 +115,10 @@ class PlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setOption(int opt, Object val) throws SocketException {
|
public void setOption(int opt, Object val) throws SocketException {
|
||||||
if (opt == SocketOptions.SO_REUSEPORT) {
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
impl.setOption(opt, val);
|
impl.setOption(opt, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getOption(int opt) throws SocketException {
|
public Object getOption(int opt) throws SocketException {
|
||||||
if (opt == SocketOptions.SO_REUSEPORT) {
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
return impl.getOption(opt);
|
return impl.getOption(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,8 +230,8 @@ class PlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
|
|
||||||
// Override methods in AbstractPlainSocketImpl that need to be implemented.
|
// Override methods in AbstractPlainSocketImpl that need to be implemented.
|
||||||
|
|
||||||
void socketCreate(boolean isServer) throws IOException {
|
void socketCreate(boolean stream) throws IOException {
|
||||||
impl.socketCreate(isServer);
|
impl.socketCreate(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void socketConnect(InetAddress address, int port, int timeout)
|
void socketConnect(InetAddress address, int port, int timeout)
|
||||||
@ -307,18 +266,10 @@ class PlainSocketImpl extends AbstractPlainSocketImpl {
|
|||||||
|
|
||||||
void socketSetOption(int cmd, boolean on, Object value)
|
void socketSetOption(int cmd, boolean on, Object value)
|
||||||
throws SocketException {
|
throws SocketException {
|
||||||
if (cmd == SocketOptions.SO_REUSEPORT) {
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
impl.socketSetOption(cmd, on, value);
|
impl.socketSetOption(cmd, on, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
|
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
|
||||||
if (opt == SocketOptions.SO_REUSEPORT) {
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
return impl.socketGetOption(opt, iaContainerObj);
|
return impl.socketGetOption(opt, iaContainerObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,324 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2007, 2018, 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.io.FileDescriptor;
|
|
||||||
import sun.net.ResourceManager;
|
|
||||||
import jdk.internal.misc.SharedSecrets;
|
|
||||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This class defines the plain SocketImpl that is used when
|
|
||||||
* the System property java.net.preferIPv4Stack is set to true.
|
|
||||||
*
|
|
||||||
* @author Chris Hegarty
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl {
|
|
||||||
|
|
||||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
|
||||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
|
||||||
|
|
||||||
// true if this socket is exclusively bound
|
|
||||||
private final boolean exclusiveBind;
|
|
||||||
|
|
||||||
// emulates SO_REUSEADDR when exclusiveBind is true
|
|
||||||
private boolean isReuseAddress;
|
|
||||||
|
|
||||||
public TwoStacksPlainSocketImpl(boolean exclBind) {
|
|
||||||
exclusiveBind = exclBind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
|
|
||||||
this.fd = fd;
|
|
||||||
exclusiveBind = exclBind;
|
|
||||||
}
|
|
||||||
|
|
||||||
void socketCreate(boolean stream) throws IOException {
|
|
||||||
if (fd == null)
|
|
||||||
throw new SocketException("Socket closed");
|
|
||||||
|
|
||||||
int newfd = socket0(stream, false /*v6 Only*/);
|
|
||||||
|
|
||||||
fdAccess.set(fd, newfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketConnect(InetAddress address, int port, int timeout)
|
|
||||||
throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
if (address == null)
|
|
||||||
throw new NullPointerException("inet address argument is null.");
|
|
||||||
|
|
||||||
int connectResult;
|
|
||||||
if (timeout <= 0) {
|
|
||||||
connectResult = connect0(nativefd, address, port);
|
|
||||||
} else {
|
|
||||||
configureBlocking(nativefd, false);
|
|
||||||
try {
|
|
||||||
connectResult = connect0(nativefd, address, port);
|
|
||||||
if (connectResult == WOULDBLOCK) {
|
|
||||||
waitForConnect(nativefd, timeout);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
configureBlocking(nativefd, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* We need to set the local port field. If bind was called
|
|
||||||
* previous to the connect (by the client) then localport field
|
|
||||||
* will already be set.
|
|
||||||
*/
|
|
||||||
if (localport == 0)
|
|
||||||
localport = localPort0(nativefd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketBind(InetAddress address, int port) throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
if (address == null)
|
|
||||||
throw new NullPointerException("inet address argument is null.");
|
|
||||||
|
|
||||||
bind0(nativefd, address, port, exclusiveBind);
|
|
||||||
if (port == 0) {
|
|
||||||
localport = localPort0(nativefd);
|
|
||||||
} else {
|
|
||||||
localport = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketListen(int backlog) throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
listen0(nativefd, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketAccept(SocketImpl s) throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
if (s == null)
|
|
||||||
throw new NullPointerException("socket is null");
|
|
||||||
|
|
||||||
int newfd = -1;
|
|
||||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
|
||||||
if (timeout <= 0) {
|
|
||||||
newfd = accept0(nativefd, isaa);
|
|
||||||
} else {
|
|
||||||
configureBlocking(nativefd, false);
|
|
||||||
try {
|
|
||||||
waitForNewConnection(nativefd, timeout);
|
|
||||||
newfd = accept0(nativefd, isaa);
|
|
||||||
if (newfd != -1) {
|
|
||||||
configureBlocking(newfd, true);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
configureBlocking(nativefd, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Update (SocketImpl)s' fd */
|
|
||||||
fdAccess.set(s.fd, newfd);
|
|
||||||
/* Update socketImpls remote port, address and localport */
|
|
||||||
InetSocketAddress isa = isaa[0];
|
|
||||||
s.port = isa.getPort();
|
|
||||||
s.address = isa.getAddress();
|
|
||||||
s.localport = localport;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int socketAvailable() throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
return available0(nativefd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
|
|
||||||
if (fd == null)
|
|
||||||
throw new SocketException("Socket closed");
|
|
||||||
|
|
||||||
if (!fd.valid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
final int nativefd = fdAccess.get(fd);
|
|
||||||
fdAccess.set(fd, -1);
|
|
||||||
close0(nativefd);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketShutdown(int howto) throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
shutdown0(nativefd, howto);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intentional fallthrough after SO_REUSEADDR
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
@Override
|
|
||||||
void socketSetOption(int opt, boolean on, Object value)
|
|
||||||
throws SocketException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
if (opt == SO_TIMEOUT) {
|
|
||||||
// Don't enable the socket option on ServerSocket as it's
|
|
||||||
// meaningless (we don't receive on a ServerSocket).
|
|
||||||
if (serverSocket == null) {
|
|
||||||
setSoTimeout0(nativefd, ((Integer)value).intValue());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
if (opt == SO_REUSEPORT) {
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
|
|
||||||
int optionValue = 0;
|
|
||||||
|
|
||||||
switch(opt) {
|
|
||||||
case SO_REUSEADDR :
|
|
||||||
if (exclusiveBind) {
|
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
|
||||||
isReuseAddress = on;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// intentional fallthrough
|
|
||||||
case TCP_NODELAY :
|
|
||||||
case SO_OOBINLINE :
|
|
||||||
case SO_KEEPALIVE :
|
|
||||||
optionValue = on ? 1 : 0;
|
|
||||||
break;
|
|
||||||
case SO_SNDBUF :
|
|
||||||
case SO_RCVBUF :
|
|
||||||
case IP_TOS :
|
|
||||||
optionValue = ((Integer)value).intValue();
|
|
||||||
break;
|
|
||||||
case SO_LINGER :
|
|
||||||
if (on) {
|
|
||||||
optionValue = ((Integer)value).intValue();
|
|
||||||
} else {
|
|
||||||
optionValue = -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default :/* shouldn't get here */
|
|
||||||
throw new SocketException("Option not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
setIntOption(nativefd, opt, optionValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
|
|
||||||
// SO_BINDADDR is not a socket option.
|
|
||||||
if (opt == SO_BINDADDR) {
|
|
||||||
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
|
|
||||||
return 0; // return value doesn't matter.
|
|
||||||
}
|
|
||||||
// SO_REUSEPORT is not supported on Windows.
|
|
||||||
if (opt == SO_REUSEPORT) {
|
|
||||||
throw new UnsupportedOperationException("unsupported option");
|
|
||||||
}
|
|
||||||
|
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
|
||||||
if (opt == SO_REUSEADDR && exclusiveBind)
|
|
||||||
return isReuseAddress? 1 : -1;
|
|
||||||
|
|
||||||
int value = getIntOption(nativefd, opt);
|
|
||||||
|
|
||||||
switch (opt) {
|
|
||||||
case TCP_NODELAY :
|
|
||||||
case SO_OOBINLINE :
|
|
||||||
case SO_KEEPALIVE :
|
|
||||||
case SO_REUSEADDR :
|
|
||||||
return (value == 0) ? -1 : 1;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void socketSendUrgentData(int data) throws IOException {
|
|
||||||
int nativefd = checkAndReturnNativeFD();
|
|
||||||
sendOOB(nativefd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int checkAndReturnNativeFD() throws SocketException {
|
|
||||||
if (fd == null || !fd.valid())
|
|
||||||
throw new SocketException("Socket closed");
|
|
||||||
|
|
||||||
return fdAccess.get(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
|
|
||||||
|
|
||||||
static {
|
|
||||||
initIDs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Native methods */
|
|
||||||
|
|
||||||
static native void initIDs();
|
|
||||||
|
|
||||||
static native int socket0(boolean stream, boolean v6Only) throws IOException;
|
|
||||||
|
|
||||||
static native void bind0(int fd, InetAddress localAddress, int localport,
|
|
||||||
boolean exclBind)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
static native int connect0(int fd, InetAddress remote, int remotePort)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
static native void waitForConnect(int fd, int timeout) throws IOException;
|
|
||||||
|
|
||||||
static native int localPort0(int fd) throws IOException;
|
|
||||||
|
|
||||||
static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
|
|
||||||
|
|
||||||
static native void listen0(int fd, int backlog) throws IOException;
|
|
||||||
|
|
||||||
static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
|
|
||||||
|
|
||||||
static native void waitForNewConnection(int fd, int timeout) throws IOException;
|
|
||||||
|
|
||||||
static native int available0(int fd) throws IOException;
|
|
||||||
|
|
||||||
static native void close0(int fd) throws IOException;
|
|
||||||
|
|
||||||
static native void shutdown0(int fd, int howto) throws IOException;
|
|
||||||
|
|
||||||
static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
|
|
||||||
|
|
||||||
static native void setSoTimeout0(int fd, int timeout) throws SocketException;
|
|
||||||
|
|
||||||
static native int getIntOption(int fd, int cmd) throws SocketException;
|
|
||||||
|
|
||||||
static native void sendOOB(int fd, int data) throws IOException;
|
|
||||||
|
|
||||||
static native void configureBlocking(int fd, boolean blocking) throws IOException;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,8 +27,8 @@
|
|||||||
#include "java_net_DualStackPlainSocketImpl.h"
|
#include "java_net_DualStackPlainSocketImpl.h"
|
||||||
#include "java_net_SocketOptions.h"
|
#include "java_net_SocketOptions.h"
|
||||||
|
|
||||||
#define SET_BLOCKING 0
|
#define SET_BLOCKING 0
|
||||||
#define SET_NONBLOCKING 1
|
#define SET_NONBLOCKING 1
|
||||||
|
|
||||||
static jclass isa_class; /* java.net.InetSocketAddress */
|
static jclass isa_class; /* java.net.InetSocketAddress */
|
||||||
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
|
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
|
||||||
@ -60,22 +60,28 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs
|
|||||||
* Signature: (ZZ)I
|
* Signature: (ZZ)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
|
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
|
||||||
(JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
|
(JNIEnv *env, jclass clazz, jboolean stream) {
|
||||||
int fd, rv, opt=0;
|
int fd, rv, opt=0;
|
||||||
|
int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
|
||||||
|
int domain = ipv6_available() ? AF_INET6 : AF_INET;
|
||||||
|
|
||||||
|
fd = NET_Socket(domain, type, 0);
|
||||||
|
|
||||||
fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "create");
|
NET_ThrowNew(env, WSAGetLastError(), "create");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
|
if (domain == AF_INET6) {
|
||||||
if (rv == SOCKET_ERROR) {
|
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "create");
|
sizeof(opt));
|
||||||
|
if (rv == SOCKET_ERROR) {
|
||||||
|
NET_ThrowNew(env, WSAGetLastError(), "create");
|
||||||
|
closesocket(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
|
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,10 +96,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
|
|||||||
{
|
{
|
||||||
SOCKETADDRESS sa;
|
SOCKETADDRESS sa;
|
||||||
int rv, sa_len = 0;
|
int rv, sa_len = 0;
|
||||||
|
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||||
&sa_len, JNI_TRUE) != 0) {
|
&sa_len, v4MappedAddress) != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
|
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
|
||||||
@ -111,10 +118,11 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
|
|||||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
|
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
|
||||||
SOCKETADDRESS sa;
|
SOCKETADDRESS sa;
|
||||||
int rv, sa_len = 0;
|
int rv, sa_len = 0;
|
||||||
|
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||||
&sa_len, JNI_TRUE) != 0) {
|
&sa_len, v4MappedAddress) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = connect(fd, &sa.sa, sa_len);
|
rv = connect(fd, &sa.sa, sa_len);
|
||||||
@ -124,7 +132,8 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
|
|||||||
return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
|
return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
|
||||||
} else if (err == WSAEADDRNOTAVAIL) {
|
} else if (err == WSAEADDRNOTAVAIL) {
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
|
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
|
||||||
"connect: Address is invalid on local machine, or port is not valid on remote machine");
|
"connect: Address is invalid on local machine,"
|
||||||
|
" or port is not valid on remote machine");
|
||||||
} else {
|
} else {
|
||||||
NET_ThrowNew(env, err, "connect");
|
NET_ThrowNew(env, err, "connect");
|
||||||
}
|
}
|
||||||
@ -200,6 +209,10 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
|
|||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||||
"Unable to establish connection");
|
"Unable to establish connection");
|
||||||
|
} else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
|
||||||
|
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
|
||||||
|
"connect: Address is invalid on local machine,"
|
||||||
|
" or port is not valid on remote machine");
|
||||||
} else {
|
} else {
|
||||||
NET_ThrowNew(env, rv, "connect");
|
NET_ThrowNew(env, rv, "connect");
|
||||||
}
|
}
|
||||||
@ -284,13 +297,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
|
|||||||
newfd = accept(fd, &sa.sa, &len);
|
newfd = accept(fd, &sa.sa, &len);
|
||||||
|
|
||||||
if (newfd == INVALID_SOCKET) {
|
if (newfd == INVALID_SOCKET) {
|
||||||
if (WSAGetLastError() == -2) {
|
NET_ThrowNew(env, WSAGetLastError(), "accept failed");
|
||||||
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
|
|
||||||
"operation interrupted");
|
|
||||||
} else {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"socket closed");
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +305,10 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
|
|||||||
|
|
||||||
ia = NET_SockaddrToInetAddress(env, &sa, &port);
|
ia = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||||
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
|
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
|
||||||
|
if (isa == NULL) {
|
||||||
|
closesocket(newfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
|
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
|
||||||
|
|
||||||
return newfd;
|
return newfd;
|
||||||
@ -400,6 +411,51 @@ Java_java_net_DualStackPlainSocketImpl_setIntOption
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: java_net_DualStackPlainSocketImpl
|
||||||
|
* Method: setSoTimeout0
|
||||||
|
* Signature: (II)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_DualStackPlainSocketImpl_setSoTimeout0
|
||||||
|
(JNIEnv *env, jclass clazz, jint fd, jint timeout)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* SO_TIMEOUT is the socket option used to specify the timeout
|
||||||
|
* for ServerSocket.accept and Socket.getInputStream().read.
|
||||||
|
* It does not typically map to a native level socket option.
|
||||||
|
* For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
|
||||||
|
* socket option to specify a receive timeout on the socket. This
|
||||||
|
* receive timeout is applicable to Socket only and the socket
|
||||||
|
* option should not be set on ServerSocket.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SO_RCVTIMEO is only supported on Microsoft's implementation
|
||||||
|
* of Windows Sockets so if WSAENOPROTOOPT returned then
|
||||||
|
* reset flag and timeout will be implemented using
|
||||||
|
* select() -- see SocketInputStream.socketRead.
|
||||||
|
*/
|
||||||
|
if (isRcvTimeoutSupported) {
|
||||||
|
/*
|
||||||
|
* Disable SO_RCVTIMEO if timeout is <= 5 second.
|
||||||
|
*/
|
||||||
|
if (timeout <= 5000) {
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
|
||||||
|
sizeof(timeout)) < 0) {
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
if (err == WSAENOPROTOOPT) {
|
||||||
|
isRcvTimeoutSupported = JNI_FALSE;
|
||||||
|
} else {
|
||||||
|
NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: java_net_DualStackPlainSocketImpl
|
* Class: java_net_DualStackPlainSocketImpl
|
||||||
* Method: getIntOption
|
* Method: getIntOption
|
||||||
@ -466,7 +522,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking
|
|||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (blocking == JNI_TRUE) {
|
if (blocking == JNI_TRUE) {
|
||||||
arg = SET_BLOCKING; // 0
|
arg = SET_BLOCKING; // 0
|
||||||
} else {
|
} else {
|
||||||
arg = SET_NONBLOCKING; // 1
|
arg = SET_NONBLOCKING; // 1
|
||||||
}
|
}
|
||||||
|
@ -1,550 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018, 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.
|
|
||||||
*/
|
|
||||||
#include "net_util.h"
|
|
||||||
|
|
||||||
#include "java_net_TwoStacksPlainSocketImpl.h"
|
|
||||||
#include "java_net_SocketOptions.h"
|
|
||||||
#include "java_net_InetAddress.h"
|
|
||||||
|
|
||||||
#define SET_BLOCKING 0
|
|
||||||
#define SET_NONBLOCKING 1
|
|
||||||
|
|
||||||
static jclass isa_class; /* java.net.InetSocketAddress */
|
|
||||||
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
|
|
||||||
|
|
||||||
/************************************************************************
|
|
||||||
* TwoStacksPlainSocketImpl
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The initIDs function is called whenever TwoStacksPlainSocketImpl is
|
|
||||||
* loaded, to cache fieldIds for efficiency. This is called everytime
|
|
||||||
* the Java class is loaded.
|
|
||||||
*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: initIDs
|
|
||||||
* Signature: ()V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_initIDs
|
|
||||||
(JNIEnv *env, jclass clazz) {
|
|
||||||
|
|
||||||
jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
|
|
||||||
CHECK_NULL(cls);
|
|
||||||
isa_class = (*env)->NewGlobalRef(env, cls);
|
|
||||||
CHECK_NULL(isa_class);
|
|
||||||
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
|
|
||||||
"(Ljava/net/InetAddress;I)V");
|
|
||||||
CHECK_NULL(isa_ctorID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: socket0
|
|
||||||
* Signature: (ZZ)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_socket0
|
|
||||||
(JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "create");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: bind0
|
|
||||||
* Signature: (ILjava/net/InetAddress;I)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_bind0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
|
|
||||||
jboolean exclBind)
|
|
||||||
{
|
|
||||||
SOCKETADDRESS sa;
|
|
||||||
int rv, sa_len = 0;
|
|
||||||
/* family is an int field of iaObj */
|
|
||||||
int family;
|
|
||||||
|
|
||||||
family = getInetAddress_family(env, iaObj);
|
|
||||||
if (family != java_net_InetAddress_IPv4) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"Protocol family not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
|
||||||
&sa_len, JNI_FALSE) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
|
|
||||||
|
|
||||||
if (rv == SOCKET_ERROR)
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: connect0
|
|
||||||
* Signature: (ILjava/net/InetAddress;I)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_connect0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
|
|
||||||
SOCKETADDRESS sa;
|
|
||||||
int rv, sa_len = 0;
|
|
||||||
int family;
|
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
|
||||||
&sa_len, JNI_FALSE) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
family = sa.sa.sa_family;
|
|
||||||
if (family != AF_INET) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"Protocol family not supported");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = connect(fd, &sa.sa, sa_len);
|
|
||||||
if (rv == SOCKET_ERROR) {
|
|
||||||
int err = WSAGetLastError();
|
|
||||||
if (err == WSAEWOULDBLOCK) {
|
|
||||||
return java_net_TwoStacksPlainSocketImpl_WOULDBLOCK;
|
|
||||||
} else if (err == WSAEADDRNOTAVAIL) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
|
|
||||||
"connect: Address is invalid on local machine, or port is not valid on remote machine");
|
|
||||||
} else {
|
|
||||||
NET_ThrowNew(env, err, "connect");
|
|
||||||
}
|
|
||||||
return -1; // return value not important.
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: waitForConnect
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForConnect
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint timeout) {
|
|
||||||
int rv, retry;
|
|
||||||
int optlen = sizeof(rv);
|
|
||||||
fd_set wr, ex;
|
|
||||||
struct timeval t;
|
|
||||||
|
|
||||||
FD_ZERO(&wr);
|
|
||||||
FD_ZERO(&ex);
|
|
||||||
FD_SET(fd, &wr);
|
|
||||||
FD_SET(fd, &ex);
|
|
||||||
t.tv_sec = timeout / 1000;
|
|
||||||
t.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait for timeout, connection established or
|
|
||||||
* connection failed.
|
|
||||||
*/
|
|
||||||
rv = select(fd+1, 0, &wr, &ex, &t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Timeout before connection is established/failed so
|
|
||||||
* we throw exception and shutdown input/output to prevent
|
|
||||||
* socket from being used.
|
|
||||||
* The socket should be closed immediately by the caller.
|
|
||||||
*/
|
|
||||||
if (rv == 0) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
|
||||||
"connect timed out");
|
|
||||||
shutdown( fd, SD_BOTH );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Socket is writable or error occurred. On some Windows editions
|
|
||||||
* the socket will appear writable when the connect fails so we
|
|
||||||
* check for error rather than writable.
|
|
||||||
*/
|
|
||||||
if (!FD_ISSET(fd, &ex)) {
|
|
||||||
return; /* connection established */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connection failed. The logic here is designed to work around
|
|
||||||
* bug on Windows NT whereby using getsockopt to obtain the
|
|
||||||
* last error (SO_ERROR) indicates there is no error. The workaround
|
|
||||||
* on NT is to allow winsock to be scheduled and this is done by
|
|
||||||
* yielding and retrying. As yielding is problematic in heavy
|
|
||||||
* load conditions we attempt up to 3 times to get the error reason.
|
|
||||||
*/
|
|
||||||
for (retry=0; retry<3; retry++) {
|
|
||||||
NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
|
|
||||||
(char*)&rv, &optlen);
|
|
||||||
if (rv) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Sleep(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rv == 0) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"Unable to establish connection");
|
|
||||||
} else if (rv == WSAEADDRNOTAVAIL) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
|
|
||||||
"connect: Address is invalid on local machine,"
|
|
||||||
" or port is not valid on remote machine");
|
|
||||||
} else {
|
|
||||||
NET_ThrowNew(env, rv, "connect");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: localPort0
|
|
||||||
* Signature: (I)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_localPort0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd) {
|
|
||||||
SOCKETADDRESS sa;
|
|
||||||
int len = sizeof(sa);
|
|
||||||
|
|
||||||
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
|
|
||||||
if (WSAGetLastError() == WSAENOTSOCK) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"Socket closed");
|
|
||||||
} else {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return (int) ntohs((u_short)GET_PORT(&sa));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: localAddress
|
|
||||||
* Signature: (ILjava/net/InetAddressContainer;)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_localAddress
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
|
|
||||||
int port;
|
|
||||||
SOCKETADDRESS sa;
|
|
||||||
int len = sizeof(sa);
|
|
||||||
jobject iaObj;
|
|
||||||
jclass iaContainerClass;
|
|
||||||
jfieldID iaFieldID;
|
|
||||||
|
|
||||||
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
|
|
||||||
CHECK_NULL(iaObj);
|
|
||||||
|
|
||||||
iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
|
|
||||||
iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
|
|
||||||
CHECK_NULL(iaFieldID);
|
|
||||||
(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: listen0
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_listen0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint backlog) {
|
|
||||||
if (listen(fd, backlog) == SOCKET_ERROR) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "listen failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: accept0
|
|
||||||
* Signature: (I[Ljava/net/InetSocketAddress;)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_accept0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
|
|
||||||
int newfd, port=0;
|
|
||||||
jobject isa;
|
|
||||||
jobject ia;
|
|
||||||
SOCKETADDRESS sa;
|
|
||||||
int len = sizeof(sa);
|
|
||||||
|
|
||||||
memset((char *)&sa, 0, len);
|
|
||||||
newfd = accept(fd, &sa.sa, &len);
|
|
||||||
|
|
||||||
if (newfd < 0) {
|
|
||||||
if (newfd == -2) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
|
|
||||||
"operation interrupted");
|
|
||||||
} else {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"socket closed");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
|
|
||||||
|
|
||||||
if (sa.sa.sa_family != AF_INET) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
|
||||||
"Protocol family not supported");
|
|
||||||
NET_SocketClose(newfd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ia = NET_SockaddrToInetAddress(env, &sa, &port);
|
|
||||||
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
|
|
||||||
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
|
|
||||||
|
|
||||||
return newfd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: waitForNewConnection
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForNewConnection
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint timeout) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv = NET_Timeout(fd, timeout);
|
|
||||||
if (rv == 0) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
|
||||||
"Accept timed out");
|
|
||||||
} else if (rv == -1) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
|
|
||||||
} else if (rv == -2) {
|
|
||||||
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
|
|
||||||
"operation interrupted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: available0
|
|
||||||
* Signature: (I)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_available0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd) {
|
|
||||||
jint available = -1;
|
|
||||||
|
|
||||||
if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "socket available");
|
|
||||||
}
|
|
||||||
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: close0
|
|
||||||
* Signature: (I)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_close0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd) {
|
|
||||||
NET_SocketClose(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: shutdown0
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_shutdown0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint howto) {
|
|
||||||
shutdown(fd, howto);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: setIntOption
|
|
||||||
* Signature: (III)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_net_TwoStacksPlainSocketImpl_setIntOption
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
|
|
||||||
{
|
|
||||||
int level = 0, opt = 0;
|
|
||||||
struct linger linger = {0, 0};
|
|
||||||
char *parg;
|
|
||||||
int arglen;
|
|
||||||
|
|
||||||
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
|
|
||||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt == java_net_SocketOptions_SO_LINGER) {
|
|
||||||
parg = (char *)&linger;
|
|
||||||
arglen = sizeof(linger);
|
|
||||||
if (value >= 0) {
|
|
||||||
linger.l_onoff = 1;
|
|
||||||
linger.l_linger = (unsigned short)value;
|
|
||||||
} else {
|
|
||||||
linger.l_onoff = 0;
|
|
||||||
linger.l_linger = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parg = (char *)&value;
|
|
||||||
arglen = sizeof(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: setSoTimeout0
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_net_TwoStacksPlainSocketImpl_setSoTimeout0
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint timeout)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* SO_TIMEOUT is the socket option used to specify the timeout
|
|
||||||
* for ServerSocket.accept and Socket.getInputStream().read.
|
|
||||||
* It does not typically map to a native level socket option.
|
|
||||||
* For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
|
|
||||||
* socket option to specify a receive timeout on the socket. This
|
|
||||||
* receive timeout is applicable to Socket only and the socket
|
|
||||||
* option should not be set on ServerSocket.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SO_RCVTIMEO is only supported on Microsoft's implementation
|
|
||||||
* of Windows Sockets so if WSAENOPROTOOPT returned then
|
|
||||||
* reset flag and timeout will be implemented using
|
|
||||||
* select() -- see SocketInputStream.socketRead.
|
|
||||||
*/
|
|
||||||
if (isRcvTimeoutSupported) {
|
|
||||||
/*
|
|
||||||
* Disable SO_RCVTIMEO if timeout is <= 5 second.
|
|
||||||
*/
|
|
||||||
if (timeout <= 5000) {
|
|
||||||
timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
|
|
||||||
sizeof(timeout)) < 0) {
|
|
||||||
int err = WSAGetLastError();
|
|
||||||
if (err == WSAENOPROTOOPT) {
|
|
||||||
isRcvTimeoutSupported = JNI_FALSE;
|
|
||||||
} else {
|
|
||||||
NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: getIntOption
|
|
||||||
* Signature: (II)I
|
|
||||||
*/
|
|
||||||
JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_getIntOption
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint cmd)
|
|
||||||
{
|
|
||||||
int level = 0, opt = 0;
|
|
||||||
int result=0;
|
|
||||||
struct linger linger = {0, 0};
|
|
||||||
char *arg;
|
|
||||||
int arglen;
|
|
||||||
|
|
||||||
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
|
|
||||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt == java_net_SocketOptions_SO_LINGER) {
|
|
||||||
arg = (char *)&linger;
|
|
||||||
arglen = sizeof(linger);
|
|
||||||
} else {
|
|
||||||
arg = (char *)&result;
|
|
||||||
arglen = sizeof(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt == java_net_SocketOptions_SO_LINGER)
|
|
||||||
return linger.l_onoff ? linger.l_linger : -1;
|
|
||||||
else
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: sendOOB
|
|
||||||
* Signature: (II)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_sendOOB
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jint data) {
|
|
||||||
jint n;
|
|
||||||
unsigned char d = (unsigned char) data & 0xff;
|
|
||||||
|
|
||||||
n = send(fd, (char *)&data, 1, MSG_OOB);
|
|
||||||
if (n == SOCKET_ERROR) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "send");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: java_net_TwoStacksPlainSocketImpl
|
|
||||||
* Method: configureBlocking
|
|
||||||
* Signature: (IZ)V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_configureBlocking
|
|
||||||
(JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
|
|
||||||
u_long arg;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (blocking == JNI_TRUE) {
|
|
||||||
arg = SET_BLOCKING; // 0
|
|
||||||
} else {
|
|
||||||
arg = SET_NONBLOCKING; // 1
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ioctlsocket(fd, FIONBIO, &arg);
|
|
||||||
if (result == SOCKET_ERROR) {
|
|
||||||
NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
|
|
||||||
}
|
|
||||||
}
|
|
71
test/jdk/java/net/Socket/RejectIPv6.java
Normal file
71
test/jdk/java/net/Socket/RejectIPv6.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8201510
|
||||||
|
* @summary Make sure IPv6 addresses are rejected when the System option
|
||||||
|
* java.net.preferIPv4Stack is set to true
|
||||||
|
* @run main/othervm -Djava.net.preferIPv4Stack=true RejectIPv6
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
public class RejectIPv6 {
|
||||||
|
|
||||||
|
public static void main(String [] argv) throws Throwable {
|
||||||
|
ServerSocket serverSocket = new ServerSocket(0);
|
||||||
|
serverSocket.setSoTimeout(1000);
|
||||||
|
int serverPort = serverSocket.getLocalPort();
|
||||||
|
Socket clientSocket = new Socket();
|
||||||
|
|
||||||
|
test("bind", () -> clientSocket.bind(
|
||||||
|
new InetSocketAddress("::1", 0)));
|
||||||
|
|
||||||
|
test("connect", () -> clientSocket.connect(
|
||||||
|
new InetSocketAddress("::1", serverPort), 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(String msg, CodeToTest codeToTest) throws Throwable {
|
||||||
|
Thread client = new Thread(() ->
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
codeToTest.run();
|
||||||
|
throw new RuntimeException(msg +
|
||||||
|
" failed to reject IPv6 address");
|
||||||
|
} catch (SocketException ok) {
|
||||||
|
} catch (Exception exc) {
|
||||||
|
throw new RuntimeException("unexpected", exc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.start();
|
||||||
|
client.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CodeToTest {
|
||||||
|
void run() throws Exception;
|
||||||
|
}
|
||||||
|
}
|
@ -25,11 +25,15 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 4476378
|
* @bug 4476378
|
||||||
* @summary Check the specific behaviour of the setReuseAddress(boolean)
|
* @summary Check the specific behaviour of the setReuseAddress(boolean)
|
||||||
* method.
|
* method.
|
||||||
* @run main Basic
|
* @run main Basic
|
||||||
* @run main/othervm -Dsun.net.useExclusiveBind Basic
|
* @run main/othervm -Dsun.net.useExclusiveBind Basic
|
||||||
|
* @run main/othervm -Dsun.net.useExclusiveBind=true Basic
|
||||||
* @run main/othervm -Djava.net.preferIPv4Stack=true Basic
|
* @run main/othervm -Djava.net.preferIPv4Stack=true Basic
|
||||||
* @run main/othervm -Dsun.net.useExclusiveBind -Djava.net.preferIPv4Stack=true Basic
|
* @run main/othervm -Dsun.net.useExclusiveBind
|
||||||
|
* -Djava.net.preferIPv4Stack=true Basic
|
||||||
|
* @run main/othervm -Dsun.net.useExclusiveBind=true
|
||||||
|
* -Djava.net.preferIPv4Stack=true Basic
|
||||||
*/
|
*/
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
|
||||||
|
@ -28,8 +28,12 @@
|
|||||||
* after a crash.
|
* after a crash.
|
||||||
* @run main Restart
|
* @run main Restart
|
||||||
* @run main/othervm -Dsun.net.useExclusiveBind Restart
|
* @run main/othervm -Dsun.net.useExclusiveBind Restart
|
||||||
|
* @run main/othervm -Dsun.net.useExclusiveBind=true Restart
|
||||||
* @run main/othervm -Djava.net.preferIPv4Stack=true Restart
|
* @run main/othervm -Djava.net.preferIPv4Stack=true Restart
|
||||||
* @run main/othervm -Dsun.net.useExclusiveBind -Djava.net.preferIPv4Stack=true Restart
|
* @run main/othervm -Dsun.net.useExclusiveBind
|
||||||
|
* -Djava.net.preferIPv4Stack=true Restart
|
||||||
|
* @run main/othervm -Dsun.net.useExclusiveBind=true
|
||||||
|
* -Djava.net.preferIPv4Stack=true Restart
|
||||||
*/
|
*/
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user