mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8253119: Remove the legacy PlainSocketImpl and PlainDatagramSocketImpl implementation
Reviewed-by: alanb, dfuchs, chegar
This commit is contained in:
parent
f485171ce8
commit
326b2e1344
78 changed files with 207 additions and 10924 deletions
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 2021, 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.util.Properties;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class defines a factory for creating DatagramSocketImpls. It defaults
|
||||
* to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls
|
||||
* by setting the impl.prefix system property.
|
||||
*
|
||||
* For Windows versions lower than Windows Vista a TwoStacksPlainDatagramSocketImpl
|
||||
* is always created. This impl supports IPv6 on these platform where available.
|
||||
*
|
||||
* On Windows platforms greater than Vista that support a dual layer TCP/IP stack
|
||||
* a DualStackPlainDatagramSocketImpl is created for DatagramSockets. For MulticastSockets
|
||||
* a TwoStacksPlainDatagramSocketImpl is always created. This is to overcome the lack
|
||||
* of behavior defined for multicasting over a dual layer socket by the RFC.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
class DefaultDatagramSocketImplFactory
|
||||
{
|
||||
private static final Class<?> prefixImplClass;
|
||||
|
||||
/* java.net.preferIPv4Stack */
|
||||
private static final boolean preferIPv4Stack;
|
||||
|
||||
/* True if exclusive binding is on for Windows */
|
||||
private static final boolean exclusiveBind;
|
||||
|
||||
static {
|
||||
Class<?> prefixImplClassLocal = null;
|
||||
|
||||
Properties props = GetPropertyAction.privilegedGetProperties();
|
||||
preferIPv4Stack = Boolean.parseBoolean(
|
||||
props.getProperty("java.net.preferIPv4Stack"));
|
||||
|
||||
String exclBindProp = props.getProperty("sun.net.useExclusiveBind", "");
|
||||
exclusiveBind = (exclBindProp.isEmpty())
|
||||
? true
|
||||
: Boolean.parseBoolean(exclBindProp);
|
||||
|
||||
// impl.prefix
|
||||
String prefix = null;
|
||||
try {
|
||||
prefix = props.getProperty("impl.prefix");
|
||||
if (prefix != null)
|
||||
prefixImplClassLocal = Class.forName("java.net."+prefix+"DatagramSocketImpl");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Can't find class: java.net." +
|
||||
prefix +
|
||||
"DatagramSocketImpl: check impl.prefix property");
|
||||
}
|
||||
|
||||
prefixImplClass = prefixImplClassLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DatagramSocketImpl</code> instance.
|
||||
*
|
||||
* @param isMulticast true if this impl is to be used for a MutlicastSocket
|
||||
* @return a new instance of <code>PlainDatagramSocketImpl</code>.
|
||||
*/
|
||||
static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast)
|
||||
throws SocketException {
|
||||
if (prefixImplClass != null) {
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
Object result = prefixImplClass.newInstance();
|
||||
return (DatagramSocketImpl) result;
|
||||
} catch (Exception e) {
|
||||
throw new SocketException("can't instantiate DatagramSocketImpl");
|
||||
}
|
||||
} else {
|
||||
// Always use TwoStacksPlainDatagramSocketImpl since we need
|
||||
// to support multicasting at DatagramSocket level
|
||||
return new TwoStacksPlainDatagramSocketImpl(exclusiveBind && !isMulticast, isMulticast);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,324 +0,0 @@
|
|||
/*
|
||||
* 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();
|
||||
|
||||
private static native int socketCreate();
|
||||
|
||||
private static native void socketBind(int fd, InetAddress localAddress,
|
||||
int localport, boolean exclBind) throws SocketException;
|
||||
|
||||
private static native void socketConnect(int fd, InetAddress address, int port)
|
||||
throws SocketException;
|
||||
|
||||
private static native void socketDisconnect(int fd);
|
||||
|
||||
private static native void socketClose(int fd);
|
||||
|
||||
private static native int socketLocalPort(int fd) throws SocketException;
|
||||
|
||||
private static native Object socketLocalAddress(int fd) throws SocketException;
|
||||
|
||||
private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet,
|
||||
int timeout, boolean connected, boolean peek) throws IOException;
|
||||
|
||||
private static native void socketSend(int fd, byte[] data, int offset, int length,
|
||||
InetAddress address, int port, boolean connected) throws IOException;
|
||||
|
||||
private static native void socketSetIntOption(int fd, int cmd,
|
||||
int optionValue) throws SocketException;
|
||||
|
||||
private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
|
||||
|
||||
native int dataAvailable();
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 2021, 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 java.security.AccessController;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.access.JavaIOFileDescriptorAccess;
|
||||
|
||||
/**
|
||||
* On Windows system we simply delegate to native methods.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
class PlainSocketImpl extends AbstractPlainSocketImpl {
|
||||
|
||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean preferIPv4Stack =
|
||||
Boolean.parseBoolean(AccessController.doPrivileged(
|
||||
new GetPropertyAction("java.net.preferIPv4Stack", "false")));
|
||||
|
||||
/**
|
||||
* Empty value of sun.net.useExclusiveBind is treated as 'true'.
|
||||
*/
|
||||
private static final boolean useExclusiveBind;
|
||||
|
||||
static {
|
||||
@SuppressWarnings("removal")
|
||||
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;
|
||||
|
||||
/**
|
||||
* Constructs an empty instance.
|
||||
*/
|
||||
PlainSocketImpl(boolean isServer) {
|
||||
super(isServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
void socketCreate(boolean stream) throws IOException {
|
||||
if (fd == null)
|
||||
throw new SocketException("Socket closed");
|
||||
|
||||
int newfd = socket0(stream);
|
||||
|
||||
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.");
|
||||
|
||||
if (preferIPv4Stack && !(address instanceof Inet4Address))
|
||||
throw new SocketException("Protocol family not supported");
|
||||
|
||||
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.");
|
||||
|
||||
if (preferIPv4Stack && !(address instanceof Inet4Address))
|
||||
throw new SocketException("Protocol family not supported");
|
||||
|
||||
bind0(nativefd, address, port, useExclusiveBind);
|
||||
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;
|
||||
if (preferIPv4Stack && !(s.address instanceof Inet4Address))
|
||||
throw new SocketException("Protocol family not supported");
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
// SO_REUSEPORT is not supported on Windows.
|
||||
if (opt == SO_REUSEPORT) {
|
||||
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 (!isServer) {
|
||||
setSoTimeout0(nativefd, ((Integer)value).intValue());
|
||||
}
|
||||
} // else timeout is implemented through select.
|
||||
return;
|
||||
}
|
||||
|
||||
int optionValue = 0;
|
||||
|
||||
switch(opt) {
|
||||
case SO_REUSEADDR:
|
||||
if (useExclusiveBind) {
|
||||
// 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 {
|
||||
|
||||
// SO_REUSEPORT is not supported on Windows.
|
||||
if (opt == SO_REUSEPORT) {
|
||||
throw new UnsupportedOperationException("unsupported option");
|
||||
}
|
||||
|
||||
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_REUSEADDR emulated when using exclusive bind
|
||||
if (opt == SO_REUSEADDR && useExclusiveBind)
|
||||
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) 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,238 +0,0 @@
|
|||
/*
|
||||
* 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.io.FileDescriptor;
|
||||
import sun.net.ResourceManager;
|
||||
|
||||
/**
|
||||
* This class defines the plain DatagramSocketImpl that is used for all
|
||||
* Windows versions lower than Vista. It adds support for IPv6 on
|
||||
* these platforms where available.
|
||||
*
|
||||
* For backward compatibility windows platforms that do not have IPv6
|
||||
* support also use this implementation, and fd1 gets set to null
|
||||
* during socket creation.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
final class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
|
||||
{
|
||||
/* Used for IPv6 on Windows only */
|
||||
private FileDescriptor fd1;
|
||||
|
||||
/*
|
||||
* Needed for ipv6 on windows because we need to know
|
||||
* if the socket was bound to ::0 or 0.0.0.0, when a caller
|
||||
* asks for it. In this case, both sockets are used, but we
|
||||
* don't know whether the caller requested ::0 or 0.0.0.0
|
||||
* and need to remember it here.
|
||||
*/
|
||||
private InetAddress anyLocalBoundAddr=null;
|
||||
|
||||
private int fduse=-1; /* saved between peek() and receive() calls */
|
||||
|
||||
/* saved between successive calls to receive, if data is detected
|
||||
* on both sockets at same time. To ensure that one socket is not
|
||||
* starved, they rotate using this field
|
||||
*/
|
||||
private int lastfd=-1;
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
TwoStacksPlainDatagramSocketImpl(boolean exclBind, boolean isMulticast) {
|
||||
super(isMulticast);
|
||||
exclusiveBind = exclBind;
|
||||
}
|
||||
|
||||
protected synchronized void create() throws SocketException {
|
||||
fd1 = new FileDescriptor();
|
||||
try {
|
||||
super.create();
|
||||
// make SocketCleanable treat fd1 as a stream socket
|
||||
// to avoid touching the counter in ResourceManager
|
||||
SocketCleanable.register(fd1, true);
|
||||
} catch (SocketException e) {
|
||||
fd1 = null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void bind(int lport, InetAddress laddr)
|
||||
throws SocketException {
|
||||
super.bind(lport, laddr);
|
||||
if (laddr.isAnyLocalAddress()) {
|
||||
anyLocalBoundAddr = laddr;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void bind0(int lport, InetAddress laddr)
|
||||
throws SocketException
|
||||
{
|
||||
// The native bind0 may close one or both of the underlying file
|
||||
// descriptors, and even create new sockets, so the safest course of
|
||||
// action is to unregister the socket cleaners, and register afterwards.
|
||||
SocketCleanable.unregister(fd);
|
||||
SocketCleanable.unregister(fd1);
|
||||
|
||||
bind0(lport, laddr, exclusiveBind);
|
||||
|
||||
SocketCleanable.register(fd, false);
|
||||
// make SocketCleanable treat fd1 as a stream socket
|
||||
// to avoid touching the counter in ResourceManager
|
||||
SocketCleanable.register(fd1, true);
|
||||
}
|
||||
|
||||
protected synchronized void receive(DatagramPacket p)
|
||||
throws IOException {
|
||||
try {
|
||||
receive0(p);
|
||||
} finally {
|
||||
fduse = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public Object getOption(int optID) throws SocketException {
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket Closed");
|
||||
}
|
||||
|
||||
if (optID == SO_BINDADDR) {
|
||||
if ((fd != null && fd1 != null) && !connected) {
|
||||
return anyLocalBoundAddr;
|
||||
}
|
||||
int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily();
|
||||
return socketLocalAddress(family);
|
||||
} else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
|
||||
return isReuseAddress;
|
||||
} else if (optID == SO_REUSEPORT) {
|
||||
// SO_REUSEPORT is not supported on Windows.
|
||||
throw new UnsupportedOperationException("unsupported option");
|
||||
} else {
|
||||
return super.getOption(optID);
|
||||
}
|
||||
}
|
||||
|
||||
protected void socketSetOption(int opt, Object val)
|
||||
throws SocketException
|
||||
{
|
||||
if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) {
|
||||
// socket already bound, emulate
|
||||
reuseAddressEmulated = true;
|
||||
isReuseAddress = (Boolean)val;
|
||||
} else if (opt == SO_REUSEPORT) {
|
||||
// SO_REUSEPORT is not supported on Windows.
|
||||
throw new UnsupportedOperationException("unsupported option");
|
||||
} else {
|
||||
socketNativeSetOption(opt, val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean isClosed() {
|
||||
return (fd == null && fd1 == null) ? true : false;
|
||||
}
|
||||
|
||||
protected void close() {
|
||||
if (fd != null || fd1 != null) {
|
||||
SocketCleanable.unregister(fd);
|
||||
SocketCleanable.unregister(fd1);
|
||||
datagramSocketClose();
|
||||
ResourceManager.afterUdpClose();
|
||||
fd = null;
|
||||
fd1 = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Native methods */
|
||||
|
||||
protected synchronized native void bind0(int lport, InetAddress laddr,
|
||||
boolean exclBind)
|
||||
throws SocketException;
|
||||
|
||||
protected native void send0(DatagramPacket p) throws IOException;
|
||||
|
||||
protected synchronized native int peek(InetAddress i) throws IOException;
|
||||
|
||||
protected synchronized native int peekData(DatagramPacket p) throws IOException;
|
||||
|
||||
protected synchronized native void receive0(DatagramPacket p)
|
||||
throws IOException;
|
||||
|
||||
protected native void setTimeToLive(int ttl) throws IOException;
|
||||
|
||||
protected native int getTimeToLive() throws IOException;
|
||||
|
||||
@Deprecated
|
||||
protected native void setTTL(byte ttl) throws IOException;
|
||||
|
||||
@Deprecated
|
||||
protected native byte getTTL() throws IOException;
|
||||
|
||||
protected native void join(InetAddress inetaddr, NetworkInterface netIf)
|
||||
throws IOException;
|
||||
|
||||
protected native void leave(InetAddress inetaddr, NetworkInterface netIf)
|
||||
throws IOException;
|
||||
|
||||
protected native void datagramSocketCreate() throws SocketException;
|
||||
|
||||
protected native void datagramSocketClose();
|
||||
|
||||
protected native void socketNativeSetOption(int opt, Object val)
|
||||
throws SocketException;
|
||||
|
||||
protected native Object socketGetOption(int opt) throws SocketException;
|
||||
|
||||
protected native void connect0(InetAddress address, int port) throws SocketException;
|
||||
|
||||
protected native Object socketLocalAddress(int family) throws SocketException;
|
||||
|
||||
protected native void disconnect0(int family);
|
||||
|
||||
native int dataAvailable();
|
||||
|
||||
/**
|
||||
* Perform class load-time initializations.
|
||||
*/
|
||||
private static native void init();
|
||||
}
|
|
@ -1,539 +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.
|
||||
*/
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_DualStackPlainDatagramSocketImpl.h"
|
||||
|
||||
/*
|
||||
* This function "purges" all outstanding ICMP port unreachable packets
|
||||
* outstanding on a socket and returns JNI_TRUE if any ICMP messages
|
||||
* have been purged. The rational for purging is to emulate normal BSD
|
||||
* behaviour whereby receiving a "connection reset" status resets the
|
||||
* socket.
|
||||
*/
|
||||
static jboolean purgeOutstandingICMP(JNIEnv *env, jint fd)
|
||||
{
|
||||
jboolean got_icmp = JNI_FALSE;
|
||||
char buf[1];
|
||||
fd_set tbl;
|
||||
struct timeval t = { 0, 0 };
|
||||
SOCKETADDRESS rmtaddr;
|
||||
int addrlen = sizeof(rmtaddr);
|
||||
|
||||
/*
|
||||
* Peek at the queue to see if there is an ICMP port unreachable. If there
|
||||
* is then receive it.
|
||||
*/
|
||||
FD_ZERO(&tbl);
|
||||
FD_SET(fd, &tbl);
|
||||
while(1) {
|
||||
if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
|
||||
break;
|
||||
}
|
||||
if (recvfrom(fd, buf, 1, MSG_PEEK,
|
||||
&rmtaddr.sa, &addrlen) != SOCKET_ERROR) {
|
||||
break;
|
||||
}
|
||||
if (WSAGetLastError() != WSAECONNRESET) {
|
||||
/* some other error - we don't care here */
|
||||
break;
|
||||
}
|
||||
|
||||
recvfrom(fd, buf, 1, 0, &rmtaddr.sa, &addrlen);
|
||||
got_icmp = JNI_TRUE;
|
||||
}
|
||||
|
||||
return got_icmp;
|
||||
}
|
||||
|
||||
static jfieldID IO_fd_fdID = NULL;
|
||||
static jfieldID pdsi_fdID = NULL;
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: initIDs
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_initIDs
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
pdsi_fdID = (*env)->GetFieldID(env, clazz, "fd",
|
||||
"Ljava/io/FileDescriptor;");
|
||||
CHECK_NULL(pdsi_fdID);
|
||||
IO_fd_fdID = NET_GetFileDescriptorID(env);
|
||||
CHECK_NULL(IO_fd_fdID);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
initInetAddressIDs(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketCreate
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCreate
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
int fd, rv, opt=0, t=TRUE;
|
||||
DWORD x1, x2; /* ignored result codes */
|
||||
|
||||
fd = (int) socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
|
||||
if (rv == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
|
||||
closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
|
||||
NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
|
||||
|
||||
/* SIO_UDP_CONNRESET fixes a "bug" introduced in Windows 2000, which
|
||||
* returns connection reset errors on unconnected UDP sockets (as well
|
||||
* as connected sockets). The solution is to only enable this feature
|
||||
* when the socket is connected.
|
||||
*/
|
||||
t = FALSE;
|
||||
WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketBind
|
||||
* Signature: (ILjava/net/InetAddress;I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
|
||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, jboolean exclBind) {
|
||||
SOCKETADDRESS sa;
|
||||
int rv, sa_len = 0;
|
||||
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||
&sa_len, JNI_TRUE) != 0) {
|
||||
return;
|
||||
}
|
||||
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
|
||||
|
||||
if (rv == SOCKET_ERROR) {
|
||||
if (WSAGetLastError() == WSAEACCES) {
|
||||
WSASetLastError(WSAEADDRINUSE);
|
||||
}
|
||||
NET_ThrowNew(env, WSAGetLastError(), "Cannot bind");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketConnect
|
||||
* Signature: (ILjava/net/InetAddress;I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect
|
||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
|
||||
SOCKETADDRESS sa;
|
||||
int rv, sa_len = 0, t;
|
||||
DWORD x1, x2; /* ignored result codes */
|
||||
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||
&sa_len, JNI_TRUE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = connect(fd, &sa.sa, sa_len);
|
||||
if (rv == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "connect");
|
||||
return;
|
||||
}
|
||||
|
||||
/* see comment in socketCreate */
|
||||
t = TRUE;
|
||||
WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketDisconnect
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketDisconnect
|
||||
(JNIEnv *env, jclass clazz, jint fd ) {
|
||||
SOCKETADDRESS sa;
|
||||
int sa_len = sizeof(sa);
|
||||
DWORD x1, x2; /* ignored result codes */
|
||||
int t = FALSE;
|
||||
|
||||
memset(&sa, 0, sa_len);
|
||||
connect(fd, &sa.sa, sa_len);
|
||||
|
||||
/* see comment in socketCreate */
|
||||
WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketClose
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketClose
|
||||
(JNIEnv *env, jclass clazz , jint fd) {
|
||||
NET_SocketClose(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketLocalPort
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalPort
|
||||
(JNIEnv *env, jclass clazz, jint fd) {
|
||||
SOCKETADDRESS sa;
|
||||
int len = sizeof(sa);
|
||||
|
||||
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "getsockname");
|
||||
return -1;
|
||||
}
|
||||
return (int) ntohs((u_short)GET_PORT(&sa));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketLocalAddress
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalAddress
|
||||
(JNIEnv *env , jclass clazz, jint fd) {
|
||||
SOCKETADDRESS sa;
|
||||
int len = sizeof(sa);
|
||||
jobject iaObj;
|
||||
int port;
|
||||
|
||||
if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||
return iaObj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketReceiveOrPeekData
|
||||
* Signature: (ILjava/net/DatagramPacket;IZZ)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketReceiveOrPeekData
|
||||
(JNIEnv *env, jclass clazz, jint fd, jobject dpObj,
|
||||
jint timeout, jboolean connected, jboolean peek) {
|
||||
SOCKETADDRESS sa;
|
||||
int sa_len = sizeof(sa);
|
||||
int port, rv, flags=0;
|
||||
char BUF[MAX_BUFFER_LEN];
|
||||
char *fullPacket;
|
||||
BOOL retry;
|
||||
jlong prevTime = 0;
|
||||
|
||||
jint packetBufferOffset, packetBufferLen;
|
||||
jbyteArray packetBuffer;
|
||||
|
||||
/* if we are only peeking. Called from peekData */
|
||||
if (peek) {
|
||||
flags = MSG_PEEK;
|
||||
}
|
||||
|
||||
packetBuffer = (*env)->GetObjectField(env, dpObj, dp_bufID);
|
||||
packetBufferOffset = (*env)->GetIntField(env, dpObj, dp_offsetID);
|
||||
packetBufferLen = (*env)->GetIntField(env, dpObj, dp_bufLengthID);
|
||||
/* Note: the buffer needn't be greater than 65,536 (0xFFFF)
|
||||
* the max size of an IP packet. Anything bigger is truncated anyway.
|
||||
*/
|
||||
if (packetBufferLen > MAX_PACKET_LEN) {
|
||||
packetBufferLen = MAX_PACKET_LEN;
|
||||
}
|
||||
|
||||
if (packetBufferLen > MAX_BUFFER_LEN) {
|
||||
fullPacket = (char *)malloc(packetBufferLen);
|
||||
if (!fullPacket) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fullPacket = &(BUF[0]);
|
||||
}
|
||||
|
||||
do {
|
||||
retry = FALSE;
|
||||
|
||||
if (timeout) {
|
||||
if (prevTime == 0) {
|
||||
prevTime = JVM_CurrentTimeMillis(env, 0);
|
||||
}
|
||||
rv = NET_Timeout(fd, timeout);
|
||||
if (rv <= 0) {
|
||||
if (rv == 0) {
|
||||
JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Receive timed out");
|
||||
} else if (rv == -1) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
}
|
||||
if (packetBufferLen > MAX_BUFFER_LEN) {
|
||||
free(fullPacket);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* receive the packet */
|
||||
rv = recvfrom(fd, fullPacket, packetBufferLen, flags,
|
||||
&sa.sa, &sa_len);
|
||||
|
||||
if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) {
|
||||
/* An icmp port unreachable - we must receive this as Windows
|
||||
* does not reset the state of the socket until this has been
|
||||
* received.
|
||||
*/
|
||||
purgeOutstandingICMP(env, fd);
|
||||
|
||||
if (connected) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
|
||||
"ICMP Port Unreachable");
|
||||
if (packetBufferLen > MAX_BUFFER_LEN)
|
||||
free(fullPacket);
|
||||
return -1;
|
||||
} else if (timeout) {
|
||||
/* Adjust timeout */
|
||||
jlong newTime = JVM_CurrentTimeMillis(env, 0);
|
||||
timeout -= (jint)(newTime - prevTime);
|
||||
if (timeout <= 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Receive timed out");
|
||||
if (packetBufferLen > MAX_BUFFER_LEN)
|
||||
free(fullPacket);
|
||||
return -1;
|
||||
}
|
||||
prevTime = newTime;
|
||||
}
|
||||
retry = TRUE;
|
||||
}
|
||||
} while (retry);
|
||||
|
||||
port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&sa));
|
||||
|
||||
/* truncate the data if the packet's length is too small */
|
||||
if (rv > packetBufferLen) {
|
||||
rv = packetBufferLen;
|
||||
}
|
||||
if (rv < 0) {
|
||||
if (WSAGetLastError() == WSAEMSGSIZE) {
|
||||
/* it is because the buffer is too small. It's UDP, it's
|
||||
* unreliable, it's all good. discard the rest of the
|
||||
* data..
|
||||
*/
|
||||
rv = packetBufferLen;
|
||||
} else {
|
||||
/* failure */
|
||||
(*env)->SetIntField(env, dpObj, dp_lengthID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == -1) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
|
||||
} else if (rv == -2) {
|
||||
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
|
||||
"operation interrupted");
|
||||
} else if (rv < 0) {
|
||||
NET_ThrowCurrent(env, "Datagram receive failed");
|
||||
} else {
|
||||
jobject packetAddress;
|
||||
/*
|
||||
* Check if there is an InetAddress already associated with this
|
||||
* packet. If so, we check if it is the same source address. We
|
||||
* can't update any existing InetAddress because it is immutable
|
||||
*/
|
||||
packetAddress = (*env)->GetObjectField(env, dpObj, dp_addressID);
|
||||
if (packetAddress != NULL) {
|
||||
if (!NET_SockaddrEqualsInetAddress(env, &sa, packetAddress)) {
|
||||
/* force a new InetAddress to be created */
|
||||
packetAddress = NULL;
|
||||
}
|
||||
}
|
||||
if (!(*env)->ExceptionCheck(env)){
|
||||
if (packetAddress == NULL ) {
|
||||
packetAddress = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||
if (packetAddress != NULL) {
|
||||
/* stuff the new InetAddress into the packet */
|
||||
(*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress);
|
||||
}
|
||||
}
|
||||
/* populate the packet */
|
||||
(*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, rv,
|
||||
(jbyte *)fullPacket);
|
||||
(*env)->SetIntField(env, dpObj, dp_portID, port);
|
||||
(*env)->SetIntField(env, dpObj, dp_lengthID, rv);
|
||||
}
|
||||
}
|
||||
|
||||
if (packetBufferLen > MAX_BUFFER_LEN) {
|
||||
free(fullPacket);
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketSend
|
||||
* Signature: (I[BIILjava/net/InetAddress;IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSend
|
||||
(JNIEnv *env, jclass clazz, jint fd, jbyteArray data, jint offset, jint length,
|
||||
jobject iaObj, jint port, jboolean connected) {
|
||||
SOCKETADDRESS sa;
|
||||
int rv, sa_len = 0;
|
||||
struct sockaddr *sap = 0;
|
||||
char BUF[MAX_BUFFER_LEN];
|
||||
char *fullPacket;
|
||||
|
||||
// if already connected, sap arg to sendto() is null
|
||||
if (!connected) {
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||
&sa_len, JNI_TRUE) != 0) {
|
||||
return;
|
||||
}
|
||||
sap = &sa.sa;
|
||||
}
|
||||
|
||||
if (length > MAX_BUFFER_LEN) {
|
||||
/* Note: the buffer needn't be greater than 65,536 (0xFFFF)
|
||||
* the max size of an IP packet. Anything bigger is truncated anyway.
|
||||
*/
|
||||
if (length > MAX_PACKET_LEN) {
|
||||
length = MAX_PACKET_LEN;
|
||||
}
|
||||
fullPacket = (char *)malloc(length);
|
||||
if (!fullPacket) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
fullPacket = &(BUF[0]);
|
||||
}
|
||||
|
||||
(*env)->GetByteArrayRegion(env, data, offset, length,
|
||||
(jbyte *)fullPacket);
|
||||
rv = sendto(fd, fullPacket, length, 0, sap, sa_len);
|
||||
if (rv == SOCKET_ERROR) {
|
||||
if (rv == -1) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (length > MAX_BUFFER_LEN) {
|
||||
free(fullPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketSetIntOption
|
||||
* Signature: (III)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
|
||||
(JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
|
||||
{
|
||||
int level = 0, opt = 0;
|
||||
|
||||
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NET_SetSockOpt(fd, level, opt, (char *)&value, sizeof(value)) < 0) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: socketGetIntOption
|
||||
* Signature: (II)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
|
||||
(JNIEnv *env, jclass clazz, jint fd, jint cmd)
|
||||
{
|
||||
int level = 0, opt = 0, result = 0;
|
||||
int result_len = sizeof(result);
|
||||
|
||||
if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NET_GetSockOpt(fd, level, opt, (void *)&result, &result_len) < 0) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_DualStackPlainDatagramSocketImpl
|
||||
* Method: dataAvailable
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_net_DualStackPlainDatagramSocketImpl_dataAvailable
|
||||
(JNIEnv *env, jobject this)
|
||||
{
|
||||
SOCKET fd;
|
||||
int rv = -1;
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
|
||||
|
||||
if (!IS_NULL(fdObj)) {
|
||||
int retval = 0;
|
||||
fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
rv = ioctlsocket(fd, FIONREAD, &retval);
|
||||
if (retval > 0) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,535 +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.
|
||||
*/
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_PlainSocketImpl.h"
|
||||
#include "java_net_SocketOptions.h"
|
||||
|
||||
#define SET_BLOCKING 0
|
||||
#define SET_NONBLOCKING 1
|
||||
|
||||
static jclass isa_class; /* java.net.InetSocketAddress */
|
||||
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: initIDs
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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);
|
||||
initInetAddressIDs(env);
|
||||
|
||||
// implement read timeout with select.
|
||||
isRcvTimeoutSupported = JNI_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socket0
|
||||
* Signature: (ZZ)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_socket0
|
||||
(JNIEnv *env, jclass clazz, jboolean stream) {
|
||||
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);
|
||||
|
||||
if (fd == INVALID_SOCKET) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "create");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (domain == AF_INET6) {
|
||||
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
|
||||
sizeof(opt));
|
||||
if (rv == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "create");
|
||||
closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: bind0
|
||||
* Signature: (ILjava/net/InetAddress;I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_bind0
|
||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
|
||||
jboolean exclBind)
|
||||
{
|
||||
SOCKETADDRESS sa;
|
||||
int rv, sa_len = 0;
|
||||
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
|
||||
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||
&sa_len, v4MappedAddress) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
|
||||
|
||||
if (rv == SOCKET_ERROR)
|
||||
NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: connect0
|
||||
* Signature: (ILjava/net/InetAddress;I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_connect0
|
||||
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
|
||||
SOCKETADDRESS sa;
|
||||
int rv, sa_len = 0;
|
||||
jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
|
||||
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
|
||||
&sa_len, v4MappedAddress) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = connect(fd, &sa.sa, sa_len);
|
||||
if (rv == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
return java_net_PlainSocketImpl_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 value not important.
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: waitForConnect
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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 (!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 {
|
||||
NET_ThrowNew(env, rv, "connect");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: localPort0
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: localAddress
|
||||
* Signature: (ILjava/net/InetAddressContainer;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: listen0
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_listen0
|
||||
(JNIEnv *env, jclass clazz, jint fd, jint backlog) {
|
||||
if (listen(fd, backlog) == SOCKET_ERROR) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "listen failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: accept0
|
||||
* Signature: (I[Ljava/net/InetSocketAddress;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_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 == INVALID_SOCKET) {
|
||||
NET_ThrowNew(env, WSAGetLastError(), "accept failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
ia = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||
if (ia == NULL){
|
||||
closesocket(newfd);
|
||||
return -1;
|
||||
}
|
||||
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
|
||||
if (isa == NULL) {
|
||||
closesocket(newfd);
|
||||
return -1;
|
||||
}
|
||||
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: waitForNewConnection
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: available0
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: close0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_close0
|
||||
(JNIEnv *env, jclass clazz, jint fd) {
|
||||
NET_SocketClose(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: shutdown0
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_shutdown0
|
||||
(JNIEnv *env, jclass clazz, jint fd, jint howto) {
|
||||
shutdown(fd, howto);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: setIntOption
|
||||
* Signature: (III)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: setSoTimeout0
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: getIntOption
|
||||
* Signature: (II)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: sendOOB
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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_PlainSocketImpl
|
||||
* Method: configureBlocking
|
||||
* Signature: (IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_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");
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 <jni.h>
|
||||
#include "net_util.h"
|
||||
#include "java_net_SocketCleanable.h"
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
// SO_REUSEPORT is not supported on Windows
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
// SO_REUSEPORT is not supported on Windows
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
// SO_REUSEPORT is not supported on Windows
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketCleanable
|
||||
* Method: cleanupClose0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_SocketCleanable_cleanupClose0(JNIEnv *env, jclass c1, jint fd)
|
||||
{
|
||||
NET_SocketClose(fd);
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2016, 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 <malloc.h>
|
||||
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_SocketInputStream.h"
|
||||
|
||||
/*************************************************************************
|
||||
* SocketInputStream
|
||||
*/
|
||||
static jfieldID IO_fd_fdID;
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketInputStream
|
||||
* Method: init
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_SocketInputStream_init(JNIEnv *env, jclass cls) {
|
||||
IO_fd_fdID = NET_GetFileDescriptorID(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketInputStream
|
||||
* Method: socketRead
|
||||
* Signature: (Ljava/io/FileDescriptor;[BIII)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
|
||||
jobject fdObj, jbyteArray data,
|
||||
jint off, jint len, jint timeout)
|
||||
{
|
||||
char BUF[MAX_BUFFER_LEN];
|
||||
char *bufP;
|
||||
jint fd, newfd, nread;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException",
|
||||
"Socket closed");
|
||||
return -1;
|
||||
}
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
if (fd == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the caller buffer is large than our stack buffer then we allocate
|
||||
* from the heap (up to a limit). If memory is exhausted we always use
|
||||
* the stack buffer.
|
||||
*/
|
||||
if (len <= MAX_BUFFER_LEN) {
|
||||
bufP = BUF;
|
||||
} else {
|
||||
if (len > MAX_HEAP_BUFFER_LEN) {
|
||||
len = MAX_HEAP_BUFFER_LEN;
|
||||
}
|
||||
bufP = (char *)malloc((size_t)len);
|
||||
if (bufP == NULL) {
|
||||
/* allocation failed so use stack buffer */
|
||||
bufP = BUF;
|
||||
len = MAX_BUFFER_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (timeout) {
|
||||
if (timeout <= 5000 || !isRcvTimeoutSupported) {
|
||||
int ret = NET_Timeout (fd, timeout);
|
||||
|
||||
if (ret <= 0) {
|
||||
if (ret == 0) {
|
||||
JNU_ThrowByName(env, "java/net/SocketTimeoutException",
|
||||
"Read timed out");
|
||||
} else if (ret == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "socket closed");
|
||||
}
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*check if the socket has been closed while we were in timeout*/
|
||||
newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
if (newfd == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nread = recv(fd, bufP, len, 0);
|
||||
if (nread > 0) {
|
||||
(*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
|
||||
} else {
|
||||
if (nread < 0) {
|
||||
int err = WSAGetLastError();
|
||||
// Check if the socket has been closed since we last checked.
|
||||
// This could be a reason for recv failing.
|
||||
if ((*env)->GetIntField(env, fdObj, IO_fd_fdID) == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
} else {
|
||||
switch (err) {
|
||||
case WSAEINTR:
|
||||
JNU_ThrowByName(env, "java/net/SocketException",
|
||||
"socket closed");
|
||||
break;
|
||||
|
||||
case WSAECONNRESET:
|
||||
case WSAESHUTDOWN:
|
||||
/*
|
||||
* Connection has been reset - Windows sometimes reports
|
||||
* the reset as a shutdown error.
|
||||
*/
|
||||
JNU_ThrowByName(env, "sun/net/ConnectionResetException",
|
||||
"");
|
||||
break;
|
||||
|
||||
case WSAETIMEDOUT :
|
||||
JNU_ThrowByName(env, "java/net/SocketTimeoutException",
|
||||
"Read timed out");
|
||||
break;
|
||||
|
||||
default:
|
||||
NET_ThrowCurrent(env, "recv failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return nread;
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2016, 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 <malloc.h>
|
||||
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_SocketOutputStream.h"
|
||||
|
||||
/************************************************************************
|
||||
* SocketOutputStream
|
||||
*/
|
||||
static jfieldID IO_fd_fdID;
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketOutputStream
|
||||
* Method: init
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {
|
||||
IO_fd_fdID = NET_GetFileDescriptorID(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketOutputStream
|
||||
* Method: socketWrite
|
||||
* Signature: (Ljava/io/FileDescriptor;[BII)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
|
||||
jobject fdObj, jbyteArray data,
|
||||
jint off, jint len) {
|
||||
char *bufP;
|
||||
char BUF[MAX_BUFFER_LEN];
|
||||
int buflen;
|
||||
int fd;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
if (IS_NULL(data)) {
|
||||
JNU_ThrowNullPointerException(env, "data argument");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use stack allocate buffer if possible. For large sizes we allocate
|
||||
* an intermediate buffer from the heap (up to a maximum). If heap is
|
||||
* unavailable just use our stack buffer.
|
||||
*/
|
||||
if (len <= MAX_BUFFER_LEN) {
|
||||
bufP = BUF;
|
||||
buflen = MAX_BUFFER_LEN;
|
||||
} else {
|
||||
buflen = min(MAX_HEAP_BUFFER_LEN, len);
|
||||
bufP = (char *)malloc((size_t)buflen);
|
||||
if (bufP == NULL) {
|
||||
bufP = BUF;
|
||||
buflen = MAX_BUFFER_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
while(len > 0) {
|
||||
int loff = 0;
|
||||
int chunkLen = min(buflen, len);
|
||||
int llen = chunkLen;
|
||||
int retry = 0;
|
||||
|
||||
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
break;
|
||||
} else {
|
||||
while(llen > 0) {
|
||||
int n = send(fd, bufP + loff, llen, 0);
|
||||
if (n > 0) {
|
||||
llen -= n;
|
||||
loff += n;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Due to a bug in Windows Sockets (observed on NT and Windows
|
||||
* 2000) it may be necessary to retry the send. The issue is that
|
||||
* on blocking sockets send/WSASend is supposed to block if there
|
||||
* is insufficient buffer space available. If there are a large
|
||||
* number of threads blocked on write due to congestion then it's
|
||||
* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
|
||||
* The workaround we use is to retry the send. If we have a
|
||||
* large buffer to send (>2k) then we retry with a maximum of
|
||||
* 2k buffer. If we hit the issue with <=2k buffer then we backoff
|
||||
* for 1 second and retry again. We repeat this up to a reasonable
|
||||
* limit before bailing out and throwing an exception. In load
|
||||
* conditions we've observed that the send will succeed after 2-3
|
||||
* attempts but this depends on network buffers associated with
|
||||
* other sockets draining.
|
||||
*/
|
||||
if (WSAGetLastError() == WSAENOBUFS) {
|
||||
if (llen > MAX_BUFFER_LEN) {
|
||||
buflen = MAX_BUFFER_LEN;
|
||||
chunkLen = MAX_BUFFER_LEN;
|
||||
llen = MAX_BUFFER_LEN;
|
||||
continue;
|
||||
}
|
||||
if (retry >= 30) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"No buffer space available - exhausted attempts to queue buffer");
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Sleep(1000);
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send failed - can be caused by close or write error.
|
||||
*/
|
||||
if (WSAGetLastError() == WSAENOTSOCK) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
|
||||
} else {
|
||||
NET_ThrowCurrent(env, "socket write error");
|
||||
}
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return;
|
||||
}
|
||||
len -= chunkLen;
|
||||
off += chunkLen;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue