mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +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,75 +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 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.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
class DefaultDatagramSocketImplFactory {
|
||||
static Class<?> prefixImplClass = null;
|
||||
|
||||
static {
|
||||
String prefix = null;
|
||||
try {
|
||||
prefix = GetPropertyAction.privilegedGetProperty("impl.prefix");
|
||||
if (prefix != null)
|
||||
prefixImplClass = 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 = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DatagramSocketImpl</code> instance.
|
||||
*
|
||||
* @param isMulticast true if this impl if for a MutlicastSocket
|
||||
* @return a new instance of a <code>DatagramSocketImpl</code>.
|
||||
*/
|
||||
static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast /*unused on unix*/)
|
||||
throws SocketException {
|
||||
if (prefixImplClass != null) {
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
DatagramSocketImpl result = (DatagramSocketImpl)prefixImplClass.newInstance();
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new SocketException("can't instantiate DatagramSocketImpl");
|
||||
}
|
||||
} else {
|
||||
return new java.net.PlainDatagramSocketImpl(isMulticast);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,108 +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.Set;
|
||||
import java.util.HashSet;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
|
||||
/*
|
||||
* On Unix systems we simply delegate to native methods.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
|
||||
{
|
||||
PlainDatagramSocketImpl(boolean isMulticast) {
|
||||
super(isMulticast);
|
||||
}
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
protected void socketSetOption(int opt, Object val) throws SocketException {
|
||||
if (opt == SocketOptions.SO_REUSEPORT &&
|
||||
!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
|
||||
throw new UnsupportedOperationException("unsupported option");
|
||||
}
|
||||
try {
|
||||
socketSetOption0(opt, val);
|
||||
} catch (SocketException se) {
|
||||
if (!connected)
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized native void bind0(int lport, InetAddress laddr)
|
||||
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 socketSetOption0(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 void disconnect0(int family);
|
||||
|
||||
native int dataAvailable();
|
||||
|
||||
/**
|
||||
* Perform class load-time initializations.
|
||||
*/
|
||||
private static native void init();
|
||||
}
|
|
@ -1,94 +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.Set;
|
||||
import java.util.HashSet;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
|
||||
/*
|
||||
* On Unix systems we simply delegate to native methods.
|
||||
*
|
||||
* @author Chris Hegarty
|
||||
*/
|
||||
|
||||
class PlainSocketImpl extends AbstractPlainSocketImpl
|
||||
{
|
||||
static {
|
||||
initProto();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty instance.
|
||||
*/
|
||||
PlainSocketImpl(boolean isServer) {
|
||||
super(isServer);
|
||||
}
|
||||
|
||||
protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
|
||||
if (opt == SocketOptions.SO_REUSEPORT &&
|
||||
!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
|
||||
throw new UnsupportedOperationException("unsupported option");
|
||||
}
|
||||
try {
|
||||
socketSetOption0(opt, b, val);
|
||||
} catch (SocketException se) {
|
||||
if (!isConnected)
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
void socketCreate(boolean stream) throws IOException {
|
||||
socketCreate(stream, isServer);
|
||||
}
|
||||
|
||||
native void socketCreate(boolean stream, boolean isServer) throws IOException;
|
||||
|
||||
native void socketConnect(InetAddress address, int port, int timeout)
|
||||
throws IOException;
|
||||
|
||||
native void socketBind(InetAddress address, int port)
|
||||
throws IOException;
|
||||
|
||||
native void socketListen(int count) throws IOException;
|
||||
|
||||
native void socketAccept(SocketImpl s) throws IOException;
|
||||
|
||||
native int socketAvailable() throws IOException;
|
||||
|
||||
native void socketClose0(boolean useDeferredClose) throws IOException;
|
||||
|
||||
native void socketShutdown(int howto) throws IOException;
|
||||
|
||||
static native void initProto();
|
||||
|
||||
native void socketSetOption0(int cmd, boolean on, Object value)
|
||||
throws SocketException;
|
||||
|
||||
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
|
||||
|
||||
native void socketSendUrgentData(int data) throws IOException;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,994 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2020, 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 <errno.h>
|
||||
|
||||
#include "jvm.h"
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_SocketOptions.h"
|
||||
#include "java_net_PlainSocketImpl.h"
|
||||
|
||||
/************************************************************************
|
||||
* PlainSocketImpl
|
||||
*/
|
||||
|
||||
static jfieldID IO_fd_fdID;
|
||||
|
||||
jfieldID psi_fdID;
|
||||
jfieldID psi_addressID;
|
||||
jfieldID psi_ipaddressID;
|
||||
jfieldID psi_portID;
|
||||
jfieldID psi_localportID;
|
||||
jfieldID psi_timeoutID;
|
||||
jfieldID psi_trafficClassID;
|
||||
jfieldID psi_fdLockID;
|
||||
jfieldID psi_closePendingID;
|
||||
|
||||
/*
|
||||
* file descriptor used for dup2
|
||||
*/
|
||||
static int marker_fd = -1;
|
||||
|
||||
|
||||
#define SET_NONBLOCKING(fd) { \
|
||||
int flags = fcntl(fd, F_GETFL); \
|
||||
flags |= O_NONBLOCK; \
|
||||
fcntl(fd, F_SETFL, flags); \
|
||||
}
|
||||
|
||||
#define SET_BLOCKING(fd) { \
|
||||
int flags = fcntl(fd, F_GETFL); \
|
||||
flags &= ~O_NONBLOCK; \
|
||||
fcntl(fd, F_SETFL, flags); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the marker file descriptor by establishing a loopback connection
|
||||
* which we shutdown but do not close the fd. The result is an fd that
|
||||
* can be used for read/write.
|
||||
*/
|
||||
static int getMarkerFD()
|
||||
{
|
||||
int sv[2];
|
||||
|
||||
#ifdef AF_UNIX
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Finally shutdown sv[0] (any reads to this fd will get
|
||||
* EOF; any writes will get an error).
|
||||
*/
|
||||
shutdown(sv[0], 2);
|
||||
close(sv[1]);
|
||||
|
||||
return sv[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the file descriptor given a PlainSocketImpl
|
||||
*/
|
||||
static int getFD(JNIEnv *env, jobject this) {
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
CHECK_NULL_RETURN(fdObj, -1);
|
||||
return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
|
||||
/*
|
||||
* The initroto function is called whenever PlainSocketImpl is
|
||||
* loaded, to cache field IDs for efficiency. This is called every time
|
||||
* the Java class is loaded.
|
||||
*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: initProto
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
|
||||
psi_fdID = (*env)->GetFieldID(env, cls , "fd",
|
||||
"Ljava/io/FileDescriptor;");
|
||||
CHECK_NULL(psi_fdID);
|
||||
psi_addressID = (*env)->GetFieldID(env, cls, "address",
|
||||
"Ljava/net/InetAddress;");
|
||||
CHECK_NULL(psi_addressID);
|
||||
psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
|
||||
CHECK_NULL(psi_portID);
|
||||
psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
|
||||
CHECK_NULL(psi_localportID);
|
||||
psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
|
||||
CHECK_NULL(psi_timeoutID);
|
||||
psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
|
||||
CHECK_NULL(psi_trafficClassID);
|
||||
psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
|
||||
"Ljava/lang/Object;");
|
||||
CHECK_NULL(psi_fdLockID);
|
||||
psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
|
||||
CHECK_NULL(psi_closePendingID);
|
||||
IO_fd_fdID = NET_GetFileDescriptorID(env);
|
||||
CHECK_NULL(IO_fd_fdID);
|
||||
|
||||
initInetAddressIDs(env);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
/* Create the marker fd used for dup2 */
|
||||
marker_fd = getMarkerFD();
|
||||
}
|
||||
|
||||
/* a global reference to the java.net.SocketException class. In
|
||||
* socketCreate, we ensure that this is initialized. This is to
|
||||
* prevent the problem where socketCreate runs out of file
|
||||
* descriptors, and is then unable to load the exception class.
|
||||
*/
|
||||
static jclass socketExceptionCls;
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketCreate
|
||||
* Signature: (ZZ)V */
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
|
||||
jboolean stream, jboolean isServer) {
|
||||
jobject fdObj, ssObj;
|
||||
int fd;
|
||||
int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
|
||||
int domain = ipv6_available() ? AF_INET6 : AF_INET;
|
||||
|
||||
if (socketExceptionCls == NULL) {
|
||||
jclass c = (*env)->FindClass(env, "java/net/SocketException");
|
||||
CHECK_NULL(c);
|
||||
socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
|
||||
CHECK_NULL(socketExceptionCls);
|
||||
}
|
||||
fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
|
||||
if (fdObj == NULL) {
|
||||
(*env)->ThrowNew(env, socketExceptionCls, "null fd object");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((fd = socket(domain, type, 0)) == -1) {
|
||||
/* note: if you run out of fds, you may not be able to load
|
||||
* the exception class, and get a NoClassDefFoundError
|
||||
* instead.
|
||||
*/
|
||||
NET_ThrowNew(env, errno, "can't create socket");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support.
|
||||
*/
|
||||
if (domain == AF_INET6 && ipv4_available()) {
|
||||
int arg = 0;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
|
||||
sizeof(int)) < 0) {
|
||||
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a server socket then enable SO_REUSEADDR
|
||||
* automatically and set to non blocking.
|
||||
*/
|
||||
if (isServer) {
|
||||
int arg = 1;
|
||||
SET_NONBLOCKING(fd);
|
||||
if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
|
||||
sizeof(arg)) < 0) {
|
||||
NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* inetAddress is the address object passed to the socket connect
|
||||
* call.
|
||||
*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketConnect
|
||||
* Signature: (Ljava/net/InetAddress;I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
|
||||
jobject iaObj, jint port,
|
||||
jint timeout)
|
||||
{
|
||||
jint localport = (*env)->GetIntField(env, this, psi_localportID);
|
||||
int len = 0;
|
||||
/* fdObj is the FileDescriptor field on this */
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
|
||||
jclass clazz = (*env)->GetObjectClass(env, this);
|
||||
|
||||
jobject fdLock;
|
||||
|
||||
jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);
|
||||
|
||||
/* fd is an int field on iaObj */
|
||||
jint fd;
|
||||
|
||||
SOCKETADDRESS sa;
|
||||
/* The result of the connection */
|
||||
int connect_rv = -1;
|
||||
|
||||
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(iaObj)) {
|
||||
JNU_ThrowNullPointerException(env, "inet address argument null.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect */
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
|
||||
JNI_TRUE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trafficClass != 0 && ipv6_available()) {
|
||||
NET_SetTrafficClass(&sa, trafficClass);
|
||||
}
|
||||
|
||||
if (timeout <= 0) {
|
||||
connect_rv = NET_Connect(fd, &sa.sa, len);
|
||||
} else {
|
||||
/*
|
||||
* A timeout was specified. We put the socket into non-blocking
|
||||
* mode, connect, and then wait for the connection to be
|
||||
* established, fail, or timeout.
|
||||
*/
|
||||
SET_NONBLOCKING(fd);
|
||||
|
||||
/* no need to use NET_Connect as non-blocking */
|
||||
connect_rv = connect(fd, &sa.sa, len);
|
||||
|
||||
/* connection not established immediately */
|
||||
if (connect_rv != 0) {
|
||||
socklen_t optlen;
|
||||
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
|
||||
jlong prevNanoTime = JVM_NanoTime(env, 0);
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
|
||||
"connect failed");
|
||||
SET_BLOCKING(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the connection to be established or a
|
||||
* timeout occurs. poll needs to handle EINTR in
|
||||
* case lwp sig handler redirects any process signals to
|
||||
* this thread.
|
||||
*/
|
||||
while (1) {
|
||||
jlong newNanoTime;
|
||||
struct pollfd pfd;
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLOUT;
|
||||
|
||||
errno = 0;
|
||||
connect_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
|
||||
|
||||
if (connect_rv >= 0) {
|
||||
break;
|
||||
}
|
||||
if (errno != EINTR) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The poll was interrupted so adjust timeout and
|
||||
* restart
|
||||
*/
|
||||
newNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= (newNanoTime - prevNanoTime);
|
||||
if (nanoTimeout < NET_NSEC_PER_MSEC) {
|
||||
connect_rv = 0;
|
||||
break;
|
||||
}
|
||||
prevNanoTime = newNanoTime;
|
||||
|
||||
} /* while */
|
||||
|
||||
if (connect_rv == 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"connect timed out");
|
||||
|
||||
/*
|
||||
* Timeout out but connection may still be established.
|
||||
* At the high level it should be closed immediately but
|
||||
* just in case we make the socket blocking again and
|
||||
* shutdown input & output.
|
||||
*/
|
||||
SET_BLOCKING(fd);
|
||||
shutdown(fd, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* has connection been established */
|
||||
optlen = sizeof(connect_rv);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
|
||||
&optlen) <0) {
|
||||
connect_rv = errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* make socket blocking again */
|
||||
SET_BLOCKING(fd);
|
||||
|
||||
/* restore errno */
|
||||
if (connect_rv != 0) {
|
||||
errno = connect_rv;
|
||||
connect_rv = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* report the appropriate exception */
|
||||
if (connect_rv < 0) {
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Linux/GNU distribution setup /etc/hosts so that
|
||||
* InetAddress.getLocalHost gets back the loopback address
|
||||
* rather than the host address. Thus a socket can be
|
||||
* bound to the loopback address and the connect will
|
||||
* fail with EADDRNOTAVAIL. In addition the Linux kernel
|
||||
* returns the wrong error in this case - it returns EINVAL
|
||||
* instead of EADDRNOTAVAIL. We handle this here so that
|
||||
* a more descriptive exception text is used.
|
||||
*/
|
||||
if (connect_rv == -1 && errno == EINVAL) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Invalid argument or cannot assign requested address");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(EPROTO)
|
||||
if (errno == EPROTO) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",
|
||||
"Protocol error");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (errno == ECONNREFUSED) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
|
||||
"Connection refused");
|
||||
} else if (errno == ETIMEDOUT) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
|
||||
"Connection timed out");
|
||||
} else if (errno == EHOSTUNREACH) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
|
||||
"Host unreachable");
|
||||
} else if (errno == EADDRNOTAVAIL) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
|
||||
"Address not available");
|
||||
} else if ((errno == EISCONN) || (errno == EBADF)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "connect failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
|
||||
|
||||
/* set the remote peer address and port */
|
||||
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
|
||||
(*env)->SetIntField(env, this, psi_portID, port);
|
||||
|
||||
/*
|
||||
* we need to initialize the local port field if bind was called
|
||||
* previously to the connect (by the client) then localport field
|
||||
* will already be initialized
|
||||
*/
|
||||
if (localport == 0) {
|
||||
/* Now that we're a connected socket, let's extract the port number
|
||||
* that the system chose for us and store it in the Socket object.
|
||||
*/
|
||||
socklen_t slen = sizeof(SOCKETADDRESS);
|
||||
if (getsockname(fd, &sa.sa, &slen) == -1) {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
|
||||
} else {
|
||||
localport = NET_GetPortFromSockaddr(&sa);
|
||||
(*env)->SetIntField(env, this, psi_localportID, localport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketBind
|
||||
* Signature: (Ljava/net/InetAddress;I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,
|
||||
jobject iaObj, jint localport) {
|
||||
|
||||
/* fdObj is the FileDescriptor field on this */
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
/* fd is an int field on fdObj */
|
||||
int fd;
|
||||
int len = 0;
|
||||
SOCKETADDRESS sa;
|
||||
|
||||
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(iaObj)) {
|
||||
JNU_ThrowNullPointerException(env, "iaObj is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* bind */
|
||||
if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa,
|
||||
&len, JNI_TRUE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NET_Bind(fd, &sa, len) < 0) {
|
||||
if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
|
||||
errno == EPERM || errno == EACCES) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
|
||||
"Bind failed");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Bind failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the address */
|
||||
(*env)->SetObjectField(env, this, psi_addressID, iaObj);
|
||||
|
||||
/* initialize the local port */
|
||||
if (localport == 0) {
|
||||
socklen_t slen = sizeof(SOCKETADDRESS);
|
||||
/* Now that we're a connected socket, let's extract the port number
|
||||
* that the system chose for us and store it in the Socket object.
|
||||
*/
|
||||
if (getsockname(fd, &sa.sa, &slen) == -1) {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
|
||||
return;
|
||||
}
|
||||
localport = NET_GetPortFromSockaddr(&sa);
|
||||
(*env)->SetIntField(env, this, psi_localportID, localport);
|
||||
} else {
|
||||
(*env)->SetIntField(env, this, psi_localportID, localport);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketListen
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketListen(JNIEnv *env, jobject this,
|
||||
jint count)
|
||||
{
|
||||
/* this FileDescriptor fd field */
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
/* fdObj's int fd field */
|
||||
int fd;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for bugid 4101691 in Solaris 2.6. See 4106600.
|
||||
* If listen backlog is Integer.MAX_VALUE then subtract 1.
|
||||
*/
|
||||
if (count == 0x7fffffff)
|
||||
count -= 1;
|
||||
|
||||
if (listen(fd, count) == -1) {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Listen failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketAccept
|
||||
* Signature: (Ljava/net/SocketImpl;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
|
||||
jobject socket)
|
||||
{
|
||||
/* fields on this */
|
||||
int port;
|
||||
jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
|
||||
jlong prevNanoTime = 0;
|
||||
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
|
||||
/* the FileDescriptor field on socket */
|
||||
jobject socketFdObj;
|
||||
/* the InetAddress field on socket */
|
||||
jobject socketAddressObj;
|
||||
|
||||
/* the ServerSocket fd int field on fdObj */
|
||||
jint fd;
|
||||
|
||||
/* accepted fd */
|
||||
jint newfd;
|
||||
|
||||
SOCKETADDRESS sa;
|
||||
socklen_t slen = sizeof(SOCKETADDRESS);
|
||||
|
||||
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(socket)) {
|
||||
JNU_ThrowNullPointerException(env, "socket is null");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* accept connection but ignore ECONNABORTED indicating that
|
||||
* connection was eagerly accepted by the OS but was reset
|
||||
* before accept() was called.
|
||||
*
|
||||
* If accept timeout in place and timeout is adjusted with
|
||||
* each ECONNABORTED or EWOULDBLOCK or EAGAIN to ensure that
|
||||
* semantics of timeout are preserved.
|
||||
*/
|
||||
for (;;) {
|
||||
int ret;
|
||||
jlong currNanoTime;
|
||||
|
||||
/* first usage pick up current time */
|
||||
if (prevNanoTime == 0 && nanoTimeout > 0) {
|
||||
prevNanoTime = JVM_NanoTime(env, 0);
|
||||
}
|
||||
|
||||
/* passing a timeout of 0 to poll will return immediately,
|
||||
but in the case of ServerSocket 0 means infinite. */
|
||||
if (timeout <= 0) {
|
||||
ret = NET_Timeout(env, fd, -1, 0);
|
||||
} else {
|
||||
ret = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime);
|
||||
}
|
||||
if (ret == 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Accept timed out");
|
||||
return;
|
||||
} else if (ret == -1) {
|
||||
if (errno == EBADF) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
|
||||
} else if (errno == ENOMEM) {
|
||||
JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Accept failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
newfd = NET_Accept(fd, &sa.sa, &slen);
|
||||
|
||||
/* connection accepted */
|
||||
if (newfd >= 0) {
|
||||
SET_BLOCKING(newfd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* non (ECONNABORTED or EWOULDBLOCK or EAGAIN) error */
|
||||
if (!(errno == ECONNABORTED || errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* ECONNABORTED or EWOULDBLOCK or EAGAIN error so adjust timeout if there is one. */
|
||||
if (nanoTimeout >= NET_NSEC_PER_MSEC) {
|
||||
currNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= (currNanoTime - prevNanoTime);
|
||||
if (nanoTimeout < NET_NSEC_PER_MSEC) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Accept timed out");
|
||||
return;
|
||||
}
|
||||
prevNanoTime = currNanoTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (newfd < 0) {
|
||||
if (newfd == -2) {
|
||||
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
|
||||
"operation interrupted");
|
||||
} else {
|
||||
if (errno == EINVAL) {
|
||||
errno = EBADF;
|
||||
}
|
||||
if (errno == EBADF) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Accept failed");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill up the remote peer port and address in the new socket structure.
|
||||
*/
|
||||
socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||
if (socketAddressObj == NULL) {
|
||||
/* should be pending exception */
|
||||
close(newfd);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate SocketImpl.fd.fd
|
||||
*/
|
||||
socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
|
||||
(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
|
||||
|
||||
(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
|
||||
(*env)->SetIntField(env, socket, psi_portID, port);
|
||||
/* also fill up the local port information */
|
||||
port = (*env)->GetIntField(env, this, psi_localportID);
|
||||
(*env)->SetIntField(env, socket, psi_localportID, port);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketAvailable
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
|
||||
int count = 0;
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
jint fd;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
return -1;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
if (NET_SocketAvailable(fd, &count) != 0) {
|
||||
if (errno == ECONNRESET) {
|
||||
JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed");
|
||||
}
|
||||
}
|
||||
return (jint) count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketClose0
|
||||
* Signature: (Z)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
|
||||
jboolean useDeferredClose) {
|
||||
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
jint fd;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"socket already closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
if (fd != -1) {
|
||||
if (useDeferredClose && marker_fd >= 0) {
|
||||
NET_Dup2(marker_fd, fd);
|
||||
} else {
|
||||
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
|
||||
NET_SocketClose(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketShutdown
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
|
||||
jint howto)
|
||||
{
|
||||
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
jint fd;
|
||||
|
||||
/*
|
||||
* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
|
||||
* -1 already?
|
||||
*/
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"socket already closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
}
|
||||
shutdown(fd, howto);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketSetOption0
|
||||
* Signature: (IZLjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketSetOption0
|
||||
(JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
|
||||
{
|
||||
int fd;
|
||||
int level, optname, optlen;
|
||||
union {
|
||||
int i;
|
||||
struct linger ling;
|
||||
} optval;
|
||||
|
||||
/*
|
||||
* Check that socket hasn't been closed
|
||||
*/
|
||||
fd = getFD(env, this);
|
||||
if (fd < 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* SO_TIMEOUT is a NOOP on Solaris/Linux
|
||||
*/
|
||||
if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the Java level socket option to the platform specific
|
||||
* level and option name.
|
||||
*/
|
||||
if (NET_MapSocketOption(cmd, &level, &optname)) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case java_net_SocketOptions_SO_SNDBUF :
|
||||
case java_net_SocketOptions_SO_RCVBUF :
|
||||
case java_net_SocketOptions_SO_LINGER :
|
||||
case java_net_SocketOptions_IP_TOS :
|
||||
{
|
||||
jclass cls;
|
||||
jfieldID fid;
|
||||
|
||||
cls = (*env)->FindClass(env, "java/lang/Integer");
|
||||
CHECK_NULL(cls);
|
||||
fid = (*env)->GetFieldID(env, cls, "value", "I");
|
||||
CHECK_NULL(fid);
|
||||
|
||||
if (cmd == java_net_SocketOptions_SO_LINGER) {
|
||||
if (on) {
|
||||
optval.ling.l_onoff = 1;
|
||||
optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
|
||||
} else {
|
||||
optval.ling.l_onoff = 0;
|
||||
optval.ling.l_linger = 0;
|
||||
}
|
||||
optlen = sizeof(optval.ling);
|
||||
} else {
|
||||
optval.i = (*env)->GetIntField(env, value, fid);
|
||||
optlen = sizeof(optval.i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Boolean -> int */
|
||||
default :
|
||||
optval.i = (on ? 1 : 0);
|
||||
optlen = sizeof(optval.i);
|
||||
|
||||
}
|
||||
|
||||
if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
|
||||
#if defined(_AIX)
|
||||
if (errno == EINVAL) {
|
||||
// On AIX setsockopt will set errno to EINVAL if the socket
|
||||
// is closed. The default error message is then confusing
|
||||
char fullMsg[128];
|
||||
jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
|
||||
return;
|
||||
}
|
||||
#endif /* _AIX */
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketGetOption
|
||||
* Signature: (ILjava/lang/Object;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketGetOption
|
||||
(JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj)
|
||||
{
|
||||
int fd;
|
||||
int level, optname, optlen;
|
||||
union {
|
||||
int i;
|
||||
struct linger ling;
|
||||
} optval;
|
||||
|
||||
/*
|
||||
* Check that socket hasn't been closed
|
||||
*/
|
||||
fd = getFD(env, this);
|
||||
if (fd < 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"Socket closed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SO_BINDADDR isn't a socket option
|
||||
*/
|
||||
if (cmd == java_net_SocketOptions_SO_BINDADDR) {
|
||||
SOCKETADDRESS sa;
|
||||
socklen_t len = sizeof(SOCKETADDRESS);
|
||||
int port;
|
||||
jobject iaObj;
|
||||
jclass iaCntrClass;
|
||||
jfieldID iaFieldID;
|
||||
|
||||
if (getsockname(fd, &sa.sa, &len) < 0) {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
|
||||
return -1;
|
||||
}
|
||||
iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
|
||||
CHECK_NULL_RETURN(iaObj, -1);
|
||||
|
||||
iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
|
||||
iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
|
||||
CHECK_NULL_RETURN(iaFieldID, -1);
|
||||
(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
|
||||
return 0; /* notice change from before */
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the Java level socket option to the platform specific
|
||||
* level and option name.
|
||||
*/
|
||||
if (NET_MapSocketOption(cmd, &level, &optname)) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Args are int except for SO_LINGER
|
||||
*/
|
||||
if (cmd == java_net_SocketOptions_SO_LINGER) {
|
||||
optlen = sizeof(optval.ling);
|
||||
} else {
|
||||
optlen = sizeof(optval.i);
|
||||
}
|
||||
|
||||
if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case java_net_SocketOptions_SO_LINGER:
|
||||
return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
|
||||
|
||||
case java_net_SocketOptions_SO_SNDBUF:
|
||||
case java_net_SocketOptions_SO_RCVBUF:
|
||||
case java_net_SocketOptions_IP_TOS:
|
||||
return optval.i;
|
||||
|
||||
default :
|
||||
return (optval.i == 0) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: java_net_PlainSocketImpl
|
||||
* Method: socketSendUrgentData
|
||||
* Signature: (B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
|
||||
jint data) {
|
||||
/* The fd field */
|
||||
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
|
||||
int n, fd;
|
||||
unsigned char d = data & 0xFF;
|
||||
|
||||
if (IS_NULL(fdObj)) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
/* Bug 4086704 - If the Socket associated with this file descriptor
|
||||
* was closed (sysCloseFD), the file descriptor is set to -1.
|
||||
*/
|
||||
if (fd == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
n = NET_Send(fd, (char *)&d, 1, MSG_OOB);
|
||||
if (n == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Write failed");
|
||||
}
|
||||
}
|
|
@ -1,60 +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 <string.h>
|
||||
|
||||
#include "net_util.h"
|
||||
#include "java_net_SocketCleanable.h"
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
|
||||
{
|
||||
return (reuseport_available()) ? JNI_TRUE : 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,170 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2017, 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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jvm.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);
|
||||
}
|
||||
|
||||
static int NET_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len, long timeout) {
|
||||
int result = 0;
|
||||
jlong prevNanoTime = JVM_NanoTime(env, 0);
|
||||
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
|
||||
while (nanoTimeout >= NET_NSEC_PER_MSEC) {
|
||||
result = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime);
|
||||
if (result <= 0) {
|
||||
if (result == 0) {
|
||||
JNU_ThrowByName(env, "java/net/SocketTimeoutException", "Read timed out");
|
||||
} else if (result == -1) {
|
||||
if (errno == EBADF) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
} else if (errno == ENOMEM) {
|
||||
JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
|
||||
} else {
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, "java/net/SocketException", "select/poll failed");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
result = NET_NonBlockingRead(fd, bufP, len);
|
||||
if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
|
||||
jlong newtNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= newtNanoTime - prevNanoTime;
|
||||
if (nanoTimeout >= NET_NSEC_PER_MSEC) {
|
||||
prevNanoTime = newtNanoTime;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_net_SocketInputStream
|
||||
* Method: socketRead0
|
||||
* 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, 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 read is greater than our stack allocated buffer then
|
||||
* we allocate from the heap (up to a limit)
|
||||
*/
|
||||
if (len > MAX_BUFFER_LEN) {
|
||||
if (len > MAX_HEAP_BUFFER_LEN) {
|
||||
len = MAX_HEAP_BUFFER_LEN;
|
||||
}
|
||||
bufP = (char *)malloc((size_t)len);
|
||||
if (bufP == NULL) {
|
||||
bufP = BUF;
|
||||
len = MAX_BUFFER_LEN;
|
||||
}
|
||||
} else {
|
||||
bufP = BUF;
|
||||
}
|
||||
if (timeout) {
|
||||
nread = NET_ReadWithTimeout(env, fd, bufP, len, timeout);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
} else {
|
||||
nread = NET_Read(fd, bufP, len);
|
||||
}
|
||||
|
||||
if (nread <= 0) {
|
||||
if (nread < 0) {
|
||||
|
||||
switch (errno) {
|
||||
case ECONNRESET:
|
||||
case EPIPE:
|
||||
JNU_ThrowByName(env, "sun/net/ConnectionResetException",
|
||||
"Connection reset");
|
||||
break;
|
||||
|
||||
case EBADF:
|
||||
JNU_ThrowByName(env, "java/net/SocketException",
|
||||
"Socket closed");
|
||||
break;
|
||||
|
||||
case EINTR:
|
||||
JNU_ThrowByName(env, "java/io/InterruptedIOException",
|
||||
"Operation interrupted");
|
||||
break;
|
||||
default:
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, "java/net/SocketException", "Read failed");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
|
||||
}
|
||||
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return nread;
|
||||
}
|
|
@ -1,126 +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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net_util.h"
|
||||
|
||||
#include "java_net_SocketOutputStream.h"
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/*
|
||||
* 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: socketWrite0
|
||||
* 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, "java/net/SocketException", "Socket closed");
|
||||
return;
|
||||
} else {
|
||||
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
|
||||
/* Bug 4086704 - If the Socket associated with this file descriptor
|
||||
* was closed (sysCloseFD), the file descriptor is set to -1.
|
||||
*/
|
||||
if (fd == -1) {
|
||||
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 heap exhausted resort to stack buffer */
|
||||
if (bufP == NULL) {
|
||||
bufP = BUF;
|
||||
buflen = MAX_BUFFER_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
while(len > 0) {
|
||||
int loff = 0;
|
||||
int chunkLen = min(buflen, len);
|
||||
int llen = chunkLen;
|
||||
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
|
||||
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
break;
|
||||
} else {
|
||||
while(llen > 0) {
|
||||
int n = NET_Send(fd, bufP + loff, llen, 0);
|
||||
if (n > 0) {
|
||||
llen -= n;
|
||||
loff += n;
|
||||
continue;
|
||||
}
|
||||
JNU_ThrowByNameWithMessageAndLastError
|
||||
(env, "java/net/SocketException", "Write failed");
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
return;
|
||||
}
|
||||
len -= chunkLen;
|
||||
off += chunkLen;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufP != BUF) {
|
||||
free(bufP);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue