/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 <string.h>
#if defined(__linux__) && !defined(USE_SELECT)
#endif
#ifdef __linux__
#endif
#include <netdb.h>
#include <stdlib.h>
#ifdef __solaris__
#include <fcntl.h>
#endif
#ifdef __linux__
#include <unistd.h>
#endif
#include "jvm.h"
#include "jni_util.h"
#include "net_util.h"
#include "java_net_SocketOptions.h"
#include "java_net_PlainSocketImpl.h"
/************************************************************************
* PlainSocketImpl
*/
/*
* file descriptor used for dup2
*/
flags |= O_NONBLOCK; \
}
flags &= ~O_NONBLOCK; \
}
/*
* 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
*/
static int getMarkerFD()
{
#ifdef AF_UNIX
return -1;
}
#else
return -1;
#endif
/*
* Finally shutdown sv[0] (any reads to this fd will get
* EOF; any writes will get an error).
*/
return sv[0];
}
/*
* Return the file descriptor given a PlainSocketImpl
*/
}
/*
* The initroto function is called whenever PlainSocketImpl is
* loaded, to cache fieldIds for efficiency. This is called everytime
* the Java class is loaded.
*
* Class: java_net_PlainSocketImpl
* Method: initProto
* Signature: ()V
*/
"Ljava/io/FileDescriptor;");
"Ljava/net/InetAddress;");
"Ljava/net/ServerSocket;");
/* 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.
*/
/*
* Class: java_net_PlainSocketImpl
* Method: socketCreate
* Signature: (Z)V */
int fd;
#ifdef AF_INET6
#else
#endif
if (socketExceptionCls == NULL) {
CHECK_NULL(c);
}
return;
}
/* note: if you run out of fds, you may not be able to load
* the exception class, and get a NoClassDefFoundError
* instead.
*/
return;
}
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
int arg = 0;
sizeof(int)) < 0) {
return;
}
}
#endif /* AF_INET6 */
/*
* If this is a server socket then enable SO_REUSEADDR
* automatically and set to non blocking.
*/
sizeof(arg)) < 0) {
return;
}
}
}
/*
* inetAddress is the address object passed to the socket connect
* call.
*
* Class: java_net_PlainSocketImpl
* Method: socketConnect
* Signature: (Ljava/net/InetAddress;I)V
*/
{
int len = 0;
/* fdObj is the FileDescriptor field on this */
/* fd is an int field on iaObj */
/* The result of the connection */
return;
} else {
}
return;
}
/* connect */
return;
}
#ifdef AF_INET6
if (trafficClass != 0 && ipv6_available()) {
}
#endif /* AF_INET6 */
if (timeout <= 0) {
#ifdef __solaris__
/* This can happen if a blocking connect is interrupted by a signal.
* See 6343810.
*/
while (1) {
#ifndef USE_SELECT
{
}
#else
{
}
#endif
if (connect_rv == JVM_IO_ERR) {
continue;
} else {
break;
}
}
if (connect_rv > 0) {
int optlen;
/* has connection been established */
optlen = sizeof(connect_rv);
(void*)&connect_rv, &optlen) <0) {
connect_rv = errno;
}
if (connect_rv != 0) {
/* restore errno */
errno = connect_rv;
}
break;
}
}
}
#endif
} 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.
*/
/* no need to use NET_Connect as non-blocking */
/* connection not established immediately */
if (connect_rv != 0) {
int optlen;
if (errno != EINPROGRESS) {
"connect failed");
return;
}
/*
* Wait for the connection to be established or a
* case lwp sig handler redirects any process signals to
* this thread.
*/
while (1) {
#ifndef USE_SELECT
{
errno = 0;
}
#else
{
struct timeval t;
errno = 0;
}
#endif
if (connect_rv >= 0) {
break;
}
break;
}
/*
* The poll was interrupted so adjust timeout and
* restart
*/
if (timeout <= 0) {
connect_rv = 0;
break;
}
} /* while */
if (connect_rv == 0) {
"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.
*/
return;
}
/* has connection been established */
optlen = sizeof(connect_rv);
&optlen) <0) {
connect_rv = errno;
}
}
/* make socket blocking again */
/* restore errno */
if (connect_rv != 0) {
errno = connect_rv;
}
}
/* report the appropriate exception */
if (connect_rv < 0) {
#ifdef __linux__
/*
* 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.
*/
"Invalid argument or cannot assign requested address");
return;
}
#endif
if (connect_rv == JVM_IO_INTR) {
"operation interrupted");
#if defined(EPROTO)
"Protocol error");
#endif
} else if (errno == ECONNREFUSED) {
"Connection refused");
"Connection timed out");
} else if (errno == EHOSTUNREACH) {
"Host unreachable");
} else if (errno == EADDRNOTAVAIL) {
"Address not available");
"Socket closed");
} else {
}
return;
}
/* set the remote peer address and 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.
*/
len = SOCKADDR_LEN;
"Error getting socket name");
} else {
}
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketBind
* Signature: (Ljava/net/InetAddress;I)V
*/
/* fdObj is the FileDescriptor field on this */
/* fd is an int field on fdObj */
int fd;
int len;
"Socket closed");
return;
} else {
}
return;
}
/* bind */
if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
return;
}
"Bind failed");
} else {
"Bind failed");
}
return;
}
/* set the address */
/* intialize the local port */
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.
*/
"Error getting socket name");
return;
}
} else {
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketListen
* Signature: (I)V
*/
{
/* this FileDescriptor fd field */
/* fdObj's int fd field */
int fd;
"Socket closed");
return;
} else {
}
/*
* 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;
"Listen failed");
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketAccept
* Signature: (Ljava/net/SocketImpl;)V
*/
{
/* fields on this */
int port;
/* the FileDescriptor field on socket */
/* the InetAddress field on socket */
/* the ServerSocket fd int field on fdObj */
/* accepted fd */
int len;
len = SOCKADDR_LEN;
"Socket closed");
return;
} else {
}
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 to ensure that semantics
* of timeout are preserved.
*/
for (;;) {
int ret;
/* first usage pick up current time */
}
/* passing a timeout of 0 to poll will return immediately,
but in the case of ServerSocket 0 means infinite. */
if (timeout <= 0) {
} else {
}
if (ret == 0) {
"Accept timed out");
return;
} else if (ret == JVM_IO_ERR) {
} else {
}
return;
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
return;
}
/* connection accepted */
if (newfd >= 0) {
break;
}
/* non (ECONNABORTED or EWOULDBLOCK) error */
break;
}
/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
if (timeout) {
if (timeout <= 0) {
"Accept timed out");
return;
}
}
}
if (newfd < 0) {
if (newfd == -2) {
"operation interrupted");
} else {
}
} else {
}
}
return;
}
/*
* fill up the remote peer port and address in the new socket structure.
*/
if (socketAddressObj == NULL) {
/* should be pending exception */
return;
}
/*
* Populate SocketImpl.fd.fd
*/
/* also fill up the local port information */
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketAvailable
* Signature: ()I
*/
"Socket closed");
return -1;
} else {
}
/* JVM_SocketAvailable returns 0 for failure, 1 for success */
if (errno == ECONNRESET) {
} else {
"ioctl FIONREAD failed");
}
}
return ret;
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketClose0
* Signature: (Z)V
*/
"socket already closed");
return;
} else {
}
if (fd != -1) {
if (useDeferredClose && marker_fd >= 0) {
} else {
}
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketShutdown
* Signature: (I)V
*/
{
/*
* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
* -1 already?
*/
"socket already closed");
return;
} else {
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketSetOption
*/
int fd;
union {
int i;
} optval;
/*
* Check that socket hasn't been closed
*/
if (fd < 0) {
"Socket closed");
return;
}
/*
*/
if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
return;
}
/*
* Map the Java level socket option to the platform specific
* level and option name.
*/
return;
}
switch (cmd) {
{
if (cmd == java_net_SocketOptions_SO_LINGER) {
if (on) {
} else {
}
} else {
}
break;
}
/* Boolean -> int */
default :
}
#ifdef __solaris__
// On Solaris setsockopt will set errno to EINVAL if the socket
// is closed. The default error message is then confusing
return;
}
#endif /* __solaris__ */
"Error setting socket option");
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketGetOption
* Signature: (I)I
*/
int fd;
union {
int i;
} optval;
/*
* Check that socket hasn't been closed
*/
if (fd < 0) {
"Socket closed");
return -1;
}
/*
* SO_BINDADDR isn't a socket option
*/
if (cmd == java_net_SocketOptions_SO_BINDADDR) {
int port;
len = SOCKADDR_LEN;
"Error getting socket name");
return -1;
}
return 0; /* notice change from before */
}
/*
* Map the Java level socket option to the platform specific
* level and option name.
*/
return -1;
}
/*
* Args are int except for SO_LINGER
*/
if (cmd == java_net_SocketOptions_SO_LINGER) {
} else {
}
"Error getting socket option");
return -1;
}
switch (cmd) {
return optval.i;
default :
}
}
/*
* Class: java_net_PlainSocketImpl
* Method: socketSendUrgentData
* Signature: (B)V
*/
/* The fd field */
int n, fd;
unsigned char d = data & 0xFF;
return;
} else {
/* Bug 4086704 - If the Socket associated with this file descriptor
* was closed (sysCloseFD), the the file descriptor is set to -1.
*/
if (fd == -1) {
return;
}
}
if (n == JVM_IO_ERR) {
return;
}
if (n == JVM_IO_INTR) {
return;
}
}