Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/PlainSocketImpl.c
32287 views
/*1* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <errno.h>26#include <string.h>27#include <sys/types.h>28#include <sys/socket.h>29#if defined(__linux__) && !defined(USE_SELECT)30#include <sys/poll.h>31#endif32#include <netinet/tcp.h> /* Defines TCP_NODELAY, needed for 2.6 */33#include <netinet/in.h>34#ifdef __linux__35#include <netinet/ip.h>36#endif37#include <netdb.h>38#include <stdlib.h>3940#ifdef __solaris__41#include <fcntl.h>42#endif43#ifdef __linux__44#include <unistd.h>45#endif4647#include "jvm.h"48#include "jni_util.h"49#include "net_util.h"5051#include "java_net_SocketOptions.h"52#include "java_net_PlainSocketImpl.h"5354/************************************************************************55* PlainSocketImpl56*/5758static jfieldID IO_fd_fdID;5960jfieldID psi_fdID;61jfieldID psi_addressID;62jfieldID psi_ipaddressID;63jfieldID psi_portID;64jfieldID psi_localportID;65jfieldID psi_timeoutID;66jfieldID psi_trafficClassID;67jfieldID psi_serverSocketID;68jfieldID psi_fdLockID;69jfieldID psi_closePendingID;7071extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);7273/*74* file descriptor used for dup275*/76static int marker_fd = -1;777879#define SET_NONBLOCKING(fd) { \80int flags = fcntl(fd, F_GETFL); \81flags |= O_NONBLOCK; \82fcntl(fd, F_SETFL, flags); \83}8485#define SET_BLOCKING(fd) { \86int flags = fcntl(fd, F_GETFL); \87flags &= ~O_NONBLOCK; \88fcntl(fd, F_SETFL, flags); \89}9091/*92* Create the marker file descriptor by establishing a loopback connection93* which we shutdown but do not close the fd. The result is an fd that94* can be used for read/write.95*/96static int getMarkerFD()97{98int sv[2];99100#ifdef AF_UNIX101if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {102return -1;103}104#else105return -1;106#endif107108/*109* Finally shutdown sv[0] (any reads to this fd will get110* EOF; any writes will get an error).111*/112JVM_SocketShutdown(sv[0], 2);113JVM_SocketClose(sv[1]);114115return sv[0];116}117118/*119* Return the file descriptor given a PlainSocketImpl120*/121static int getFD(JNIEnv *env, jobject this) {122jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);123CHECK_NULL_RETURN(fdObj, -1);124return (*env)->GetIntField(env, fdObj, IO_fd_fdID);125}126127/*128* The initroto function is called whenever PlainSocketImpl is129* loaded, to cache field IDs for efficiency. This is called every time130* the Java class is loaded.131*132* Class: java_net_PlainSocketImpl133* Method: initProto134* Signature: ()V135*/136JNIEXPORT void JNICALL137Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {138psi_fdID = (*env)->GetFieldID(env, cls , "fd",139"Ljava/io/FileDescriptor;");140CHECK_NULL(psi_fdID);141psi_addressID = (*env)->GetFieldID(env, cls, "address",142"Ljava/net/InetAddress;");143CHECK_NULL(psi_addressID);144psi_portID = (*env)->GetFieldID(env, cls, "port", "I");145CHECK_NULL(psi_portID);146psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");147CHECK_NULL(psi_localportID);148psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");149CHECK_NULL(psi_timeoutID);150psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");151CHECK_NULL(psi_trafficClassID);152psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",153"Ljava/net/ServerSocket;");154CHECK_NULL(psi_serverSocketID);155psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",156"Ljava/lang/Object;");157CHECK_NULL(psi_fdLockID);158psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");159CHECK_NULL(psi_closePendingID);160IO_fd_fdID = NET_GetFileDescriptorID(env);161CHECK_NULL(IO_fd_fdID);162163initInetAddressIDs(env);164JNU_CHECK_EXCEPTION(env);165166/* Create the marker fd used for dup2 */167marker_fd = getMarkerFD();168}169170/* a global reference to the java.net.SocketException class. In171* socketCreate, we ensure that this is initialized. This is to172* prevent the problem where socketCreate runs out of file173* descriptors, and is then unable to load the exception class.174*/175static jclass socketExceptionCls;176177/*178* Class: java_net_PlainSocketImpl179* Method: socketCreate180* Signature: (Z)V */181JNIEXPORT void JNICALL182Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,183jboolean stream) {184jobject fdObj, ssObj;185int fd;186int type = (stream ? SOCK_STREAM : SOCK_DGRAM);187#ifdef AF_INET6188int domain = ipv6_available() ? AF_INET6 : AF_INET;189#else190int domain = AF_INET;191#endif192193if (socketExceptionCls == NULL) {194jclass c = (*env)->FindClass(env, "java/net/SocketException");195CHECK_NULL(c);196socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);197CHECK_NULL(socketExceptionCls);198}199fdObj = (*env)->GetObjectField(env, this, psi_fdID);200201if (fdObj == NULL) {202(*env)->ThrowNew(env, socketExceptionCls, "null fd object");203return;204}205206if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) {207/* note: if you run out of fds, you may not be able to load208* the exception class, and get a NoClassDefFoundError209* instead.210*/211NET_ThrowNew(env, errno, "can't create socket");212return;213}214215#ifdef AF_INET6216/* Disable IPV6_V6ONLY to ensure dual-socket support */217if (domain == AF_INET6) {218int arg = 0;219if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,220sizeof(int)) < 0) {221NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");222close(fd);223return;224}225}226#endif /* AF_INET6 */227228/*229* If this is a server socket then enable SO_REUSEADDR230* automatically and set to non blocking.231*/232ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);233if (ssObj != NULL) {234int arg = 1;235SET_NONBLOCKING(fd);236if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,237sizeof(arg)) < 0) {238NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");239close(fd);240return;241}242}243244(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);245}246247/*248* inetAddress is the address object passed to the socket connect249* call.250*251* Class: java_net_PlainSocketImpl252* Method: socketConnect253* Signature: (Ljava/net/InetAddress;I)V254*/255JNIEXPORT void JNICALL256Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,257jobject iaObj, jint port,258jint timeout)259{260jint localport = (*env)->GetIntField(env, this, psi_localportID);261int len = 0;262263/* fdObj is the FileDescriptor field on this */264jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);265266jclass clazz = (*env)->GetObjectClass(env, this);267268jobject fdLock;269270jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);271272/* fd is an int field on iaObj */273jint fd;274275SOCKADDR him;276/* The result of the connection */277int connect_rv = -1;278279if (IS_NULL(fdObj)) {280JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");281return;282} else {283fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);284}285if (IS_NULL(iaObj)) {286JNU_ThrowNullPointerException(env, "inet address argument null.");287return;288}289290/* connect */291if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {292return;293}294setDefaultScopeID(env, (struct sockaddr *)&him);295296#ifdef AF_INET6297if (trafficClass != 0 && ipv6_available()) {298NET_SetTrafficClass((struct sockaddr *)&him, trafficClass);299}300#endif /* AF_INET6 */301if (timeout <= 0) {302connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len);303#ifdef __solaris__304if (connect_rv == JVM_IO_ERR && errno == EINPROGRESS ) {305306/* This can happen if a blocking connect is interrupted by a signal.307* See 6343810.308*/309while (1) {310#ifndef USE_SELECT311{312struct pollfd pfd;313pfd.fd = fd;314pfd.events = POLLOUT;315316connect_rv = NET_Poll(&pfd, 1, -1);317}318#else319{320fd_set wr, ex;321322FD_ZERO(&wr);323FD_SET(fd, &wr);324FD_ZERO(&ex);325FD_SET(fd, &ex);326327connect_rv = NET_Select(fd+1, 0, &wr, &ex, 0);328}329#endif330331if (connect_rv == JVM_IO_ERR) {332if (errno == EINTR) {333continue;334} else {335break;336}337}338if (connect_rv > 0) {339int optlen;340/* has connection been established */341optlen = sizeof(connect_rv);342if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,343(void*)&connect_rv, &optlen) <0) {344connect_rv = errno;345}346347if (connect_rv != 0) {348/* restore errno */349errno = connect_rv;350connect_rv = JVM_IO_ERR;351}352break;353}354}355}356#endif357} else {358/*359* A timeout was specified. We put the socket into non-blocking360* mode, connect, and then wait for the connection to be361* established, fail, or timeout.362*/363SET_NONBLOCKING(fd);364365/* no need to use NET_Connect as non-blocking */366connect_rv = connect(fd, (struct sockaddr *)&him, len);367368/* connection not established immediately */369if (connect_rv != 0) {370int optlen;371jlong prevTime = JVM_CurrentTimeMillis(env, 0);372373if (errno != EINPROGRESS) {374NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",375"connect failed");376SET_BLOCKING(fd);377return;378}379380/*381* Wait for the connection to be established or a382* timeout occurs. poll/select needs to handle EINTR in383* case lwp sig handler redirects any process signals to384* this thread.385*/386while (1) {387jlong newTime;388#ifndef USE_SELECT389{390struct pollfd pfd;391pfd.fd = fd;392pfd.events = POLLOUT;393394errno = 0;395connect_rv = NET_Poll(&pfd, 1, timeout);396}397#else398{399fd_set wr, ex;400struct timeval t;401402t.tv_sec = timeout / 1000;403t.tv_usec = (timeout % 1000) * 1000;404405FD_ZERO(&wr);406FD_SET(fd, &wr);407FD_ZERO(&ex);408FD_SET(fd, &ex);409410errno = 0;411connect_rv = NET_Select(fd+1, 0, &wr, &ex, &t);412}413#endif414415if (connect_rv >= 0) {416break;417}418if (errno != EINTR) {419break;420}421422/*423* The poll was interrupted so adjust timeout and424* restart425*/426newTime = JVM_CurrentTimeMillis(env, 0);427timeout -= (newTime - prevTime);428if (timeout <= 0) {429connect_rv = 0;430break;431}432prevTime = newTime;433434} /* while */435436if (connect_rv == 0) {437JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",438"connect timed out");439440/*441* Timeout out but connection may still be established.442* At the high level it should be closed immediately but443* just in case we make the socket blocking again and444* shutdown input & output.445*/446SET_BLOCKING(fd);447JVM_SocketShutdown(fd, 2);448return;449}450451/* has connection been established */452optlen = sizeof(connect_rv);453if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,454&optlen) <0) {455connect_rv = errno;456}457}458459/* make socket blocking again */460SET_BLOCKING(fd);461462/* restore errno */463if (connect_rv != 0) {464errno = connect_rv;465connect_rv = JVM_IO_ERR;466}467}468469/* report the appropriate exception */470if (connect_rv < 0) {471472#ifdef __linux__473/*474* Linux/GNU distribution setup /etc/hosts so that475* InetAddress.getLocalHost gets back the loopback address476* rather than the host address. Thus a socket can be477* bound to the loopback address and the connect will478* fail with EADDRNOTAVAIL. In addition the Linux kernel479* returns the wrong error in this case - it returns EINVAL480* instead of EADDRNOTAVAIL. We handle this here so that481* a more descriptive exception text is used.482*/483if (connect_rv == JVM_IO_ERR && errno == EINVAL) {484JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",485"Invalid argument or cannot assign requested address");486return;487}488#endif489if (connect_rv == JVM_IO_INTR) {490JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",491"operation interrupted");492#if defined(EPROTO)493} else if (errno == EPROTO) {494NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",495"Protocol error");496#endif497} else if (errno == ECONNREFUSED) {498NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",499"Connection refused");500} else if (errno == ETIMEDOUT) {501NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",502"Connection timed out");503} else if (errno == EHOSTUNREACH) {504NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",505"Host unreachable");506} else if (errno == EADDRNOTAVAIL) {507NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",508"Address not available");509} else if ((errno == EISCONN) || (errno == EBADF)) {510JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",511"Socket closed");512} else {513NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "connect failed");514}515return;516}517518(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);519520/* set the remote peer address and port */521(*env)->SetObjectField(env, this, psi_addressID, iaObj);522(*env)->SetIntField(env, this, psi_portID, port);523524/*525* we need to initialize the local port field if bind was called526* previously to the connect (by the client) then localport field527* will already be initialized528*/529if (localport == 0) {530/* Now that we're a connected socket, let's extract the port number531* that the system chose for us and store it in the Socket object.532*/533len = SOCKADDR_LEN;534if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {535NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",536"Error getting socket name");537} else {538localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);539(*env)->SetIntField(env, this, psi_localportID, localport);540}541}542}543544/*545* Class: java_net_PlainSocketImpl546* Method: socketBind547* Signature: (Ljava/net/InetAddress;I)V548*/549JNIEXPORT void JNICALL550Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,551jobject iaObj, jint localport) {552553/* fdObj is the FileDescriptor field on this */554jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);555/* fd is an int field on fdObj */556int fd;557int len;558SOCKADDR him;559560if (IS_NULL(fdObj)) {561JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",562"Socket closed");563return;564} else {565fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);566}567if (IS_NULL(iaObj)) {568JNU_ThrowNullPointerException(env, "iaObj is null.");569return;570}571572/* bind */573if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {574return;575}576setDefaultScopeID(env, (struct sockaddr *)&him);577578if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {579if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||580errno == EPERM || errno == EACCES) {581NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",582"Bind failed");583} else {584NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",585"Bind failed");586}587return;588}589590/* set the address */591(*env)->SetObjectField(env, this, psi_addressID, iaObj);592593/* initialize the local port */594if (localport == 0) {595/* Now that we're a connected socket, let's extract the port number596* that the system chose for us and store it in the Socket object.597*/598if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {599NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",600"Error getting socket name");601return;602}603localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);604(*env)->SetIntField(env, this, psi_localportID, localport);605} else {606(*env)->SetIntField(env, this, psi_localportID, localport);607}608}609610/*611* Class: java_net_PlainSocketImpl612* Method: socketListen613* Signature: (I)V614*/615JNIEXPORT void JNICALL616Java_java_net_PlainSocketImpl_socketListen (JNIEnv *env, jobject this,617jint count)618{619/* this FileDescriptor fd field */620jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);621/* fdObj's int fd field */622int fd;623624if (IS_NULL(fdObj)) {625JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",626"Socket closed");627return;628} else {629fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);630}631632/*633* Workaround for bugid 4101691 in Solaris 2.6. See 4106600.634* If listen backlog is Integer.MAX_VALUE then subtract 1.635*/636if (count == 0x7fffffff)637count -= 1;638639if (JVM_Listen(fd, count) == JVM_IO_ERR) {640NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",641"Listen failed");642}643}644645/*646* Class: java_net_PlainSocketImpl647* Method: socketAccept648* Signature: (Ljava/net/SocketImpl;)V649*/650JNIEXPORT void JNICALL651Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,652jobject socket)653{654/* fields on this */655int port;656jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);657jlong prevTime = 0;658jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);659660/* the FileDescriptor field on socket */661jobject socketFdObj;662/* the InetAddress field on socket */663jobject socketAddressObj;664665/* the ServerSocket fd int field on fdObj */666jint fd;667668/* accepted fd */669jint newfd;670671SOCKADDR him;672int len;673674len = SOCKADDR_LEN;675676if (IS_NULL(fdObj)) {677JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",678"Socket closed");679return;680} else {681fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);682}683if (IS_NULL(socket)) {684JNU_ThrowNullPointerException(env, "socket is null");685return;686}687688/*689* accept connection but ignore ECONNABORTED indicating that690* connection was eagerly accepted by the OS but was reset691* before accept() was called.692*693* If accept timeout in place and timeout is adjusted with694* each ECONNABORTED or EWOULDBLOCK to ensure that semantics695* of timeout are preserved.696*/697for (;;) {698int ret;699700/* first usage pick up current time */701if (prevTime == 0 && timeout > 0) {702prevTime = JVM_CurrentTimeMillis(env, 0);703}704705/* passing a timeout of 0 to poll will return immediately,706but in the case of ServerSocket 0 means infinite. */707if (timeout <= 0) {708ret = NET_Timeout(fd, -1);709} else {710ret = NET_Timeout(fd, timeout);711}712if (ret == 0) {713JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",714"Accept timed out");715return;716} else if (ret == JVM_IO_ERR) {717if (errno == EBADF) {718JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");719} else if (errno == ENOMEM) {720JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");721} else {722NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");723}724return;725} else if (ret == JVM_IO_INTR) {726JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",727"operation interrupted");728return;729}730731newfd = NET_Accept(fd, (struct sockaddr *)&him, (jint*)&len);732733/* connection accepted */734if (newfd >= 0) {735SET_BLOCKING(newfd);736break;737}738739/* non (ECONNABORTED or EWOULDBLOCK) error */740if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) {741break;742}743744/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */745if (timeout) {746jlong currTime = JVM_CurrentTimeMillis(env, 0);747timeout -= (currTime - prevTime);748749if (timeout <= 0) {750JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",751"Accept timed out");752return;753}754prevTime = currTime;755}756}757758if (newfd < 0) {759if (newfd == -2) {760JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",761"operation interrupted");762} else {763if (errno == EINVAL) {764errno = EBADF;765}766if (errno == EBADF) {767JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");768} else {769NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");770}771}772return;773}774775/*776* fill up the remote peer port and address in the new socket structure.777*/778socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);779if (socketAddressObj == NULL) {780/* should be pending exception */781close(newfd);782return;783}784785/*786* Populate SocketImpl.fd.fd787*/788socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);789(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);790791(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);792(*env)->SetIntField(env, socket, psi_portID, port);793/* also fill up the local port information */794port = (*env)->GetIntField(env, this, psi_localportID);795(*env)->SetIntField(env, socket, psi_localportID, port);796}797798799/*800* Class: java_net_PlainSocketImpl801* Method: socketAvailable802* Signature: ()I803*/804JNIEXPORT jint JNICALL805Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {806807jint ret = -1;808jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);809jint fd;810811if (IS_NULL(fdObj)) {812JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",813"Socket closed");814return -1;815} else {816fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);817}818/* JVM_SocketAvailable returns 0 for failure, 1 for success */819if (!JVM_SocketAvailable(fd, &ret)){820if (errno == ECONNRESET) {821JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");822} else {823NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",824"ioctl FIONREAD failed");825}826}827return ret;828}829830/*831* Class: java_net_PlainSocketImpl832* Method: socketClose0833* Signature: (Z)V834*/835JNIEXPORT void JNICALL836Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,837jboolean useDeferredClose) {838839jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);840jint fd;841842if (IS_NULL(fdObj)) {843JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",844"socket already closed");845return;846} else {847fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);848}849if (fd != -1) {850if (useDeferredClose && marker_fd >= 0) {851NET_Dup2(marker_fd, fd);852} else {853(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);854NET_SocketClose(fd);855}856}857}858859/*860* Class: java_net_PlainSocketImpl861* Method: socketShutdown862* Signature: (I)V863*/864JNIEXPORT void JNICALL865Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,866jint howto)867{868869jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);870jint fd;871872/*873* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being874* -1 already?875*/876if (IS_NULL(fdObj)) {877JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",878"socket already closed");879return;880} else {881fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);882}883JVM_SocketShutdown(fd, howto);884}885886887/*888* Class: java_net_PlainSocketImpl889* Method: socketSetOption0890* Signature: (IZLjava/lang/Object;)V891*/892JNIEXPORT void JNICALL893Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,894jint cmd, jboolean on,895jobject value) {896int fd;897int level, optname, optlen;898union {899int i;900struct linger ling;901} optval;902903/*904* Check that socket hasn't been closed905*/906fd = getFD(env, this);907if (fd < 0) {908JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",909"Socket closed");910return;911}912913/*914* SO_TIMEOUT is a NOOP on Solaris/Linux915*/916if (cmd == java_net_SocketOptions_SO_TIMEOUT) {917return;918}919920/*921* Map the Java level socket option to the platform specific922* level and option name.923*/924if (NET_MapSocketOption(cmd, &level, &optname)) {925JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");926return;927}928929switch (cmd) {930case java_net_SocketOptions_SO_SNDBUF :931case java_net_SocketOptions_SO_RCVBUF :932case java_net_SocketOptions_SO_LINGER :933case java_net_SocketOptions_IP_TOS :934{935jclass cls;936jfieldID fid;937938cls = (*env)->FindClass(env, "java/lang/Integer");939CHECK_NULL(cls);940fid = (*env)->GetFieldID(env, cls, "value", "I");941CHECK_NULL(fid);942943if (cmd == java_net_SocketOptions_SO_LINGER) {944if (on) {945optval.ling.l_onoff = 1;946optval.ling.l_linger = (*env)->GetIntField(env, value, fid);947} else {948optval.ling.l_onoff = 0;949optval.ling.l_linger = 0;950}951optlen = sizeof(optval.ling);952} else {953optval.i = (*env)->GetIntField(env, value, fid);954optlen = sizeof(optval.i);955}956957break;958}959960/* Boolean -> int */961default :962optval.i = (on ? 1 : 0);963optlen = sizeof(optval.i);964965}966967if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {968#if defined(__solaris__) || defined(_AIX)969if (errno == EINVAL) {970// On Solaris setsockopt will set errno to EINVAL if the socket971// is closed. The default error message is then confusing972char fullMsg[128];973jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");974JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);975return;976}977#endif /* __solaris__ */978NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",979"Error setting socket option");980}981}982983/*984* Class: java_net_PlainSocketImpl985* Method: socketGetOption986* Signature: (I)I987*/988JNIEXPORT jint JNICALL989Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,990jint cmd, jobject iaContainerObj) {991992int fd;993int level, optname, optlen;994union {995int i;996struct linger ling;997} optval;998999/*1000* Check that socket hasn't been closed1001*/1002fd = getFD(env, this);1003if (fd < 0) {1004JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",1005"Socket closed");1006return -1;1007}10081009/*1010* SO_BINDADDR isn't a socket option1011*/1012if (cmd == java_net_SocketOptions_SO_BINDADDR) {1013SOCKADDR him;1014socklen_t len = 0;1015int port;1016jobject iaObj;1017jclass iaCntrClass;1018jfieldID iaFieldID;10191020len = SOCKADDR_LEN;10211022if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {1023NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",1024"Error getting socket name");1025return -1;1026}1027iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);1028CHECK_NULL_RETURN(iaObj, -1);10291030iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);1031iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");1032CHECK_NULL_RETURN(iaFieldID, -1);1033(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);1034return 0; /* notice change from before */1035}10361037/*1038* Map the Java level socket option to the platform specific1039* level and option name.1040*/1041if (NET_MapSocketOption(cmd, &level, &optname)) {1042JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");1043return -1;1044}10451046/*1047* Args are int except for SO_LINGER1048*/1049if (cmd == java_net_SocketOptions_SO_LINGER) {1050optlen = sizeof(optval.ling);1051} else {1052optlen = sizeof(optval.i);1053}10541055if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {1056NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",1057"Error getting socket option");1058return -1;1059}10601061switch (cmd) {1062case java_net_SocketOptions_SO_LINGER:1063return (optval.ling.l_onoff ? optval.ling.l_linger: -1);10641065case java_net_SocketOptions_SO_SNDBUF:1066case java_net_SocketOptions_SO_RCVBUF:1067case java_net_SocketOptions_IP_TOS:1068return optval.i;10691070default :1071return (optval.i == 0) ? -1 : 1;1072}1073}107410751076/*1077* Class: java_net_PlainSocketImpl1078* Method: socketSendUrgentData1079* Signature: (B)V1080*/1081JNIEXPORT void JNICALL1082Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,1083jint data) {1084/* The fd field */1085jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);1086int n, fd;1087unsigned char d = data & 0xFF;10881089if (IS_NULL(fdObj)) {1090JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");1091return;1092} else {1093fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);1094/* Bug 4086704 - If the Socket associated with this file descriptor1095* was closed (sysCloseFD), the the file descriptor is set to -1.1096*/1097if (fd == -1) {1098JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");1099return;1100}11011102}1103n = JVM_Send(fd, (char *)&d, 1, MSG_OOB);1104if (n == JVM_IO_ERR) {1105NET_ThrowByNameWithLastError(env, "java/io/IOException", "Write failed");1106return;1107}1108if (n == JVM_IO_INTR) {1109JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);1110return;1111}1112}111311141115