Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c
32287 views
/*1* Copyright (c) 1997, 2018, 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 <windows.h>26#include <winsock2.h>27#include <ctype.h>28#include <stdio.h>29#include <stdlib.h>30#include <malloc.h>31#include <sys/types.h>3233#include "java_net_SocketOptions.h"34#include "java_net_TwoStacksPlainSocketImpl.h"35#include "java_net_InetAddress.h"36#include "java_io_FileDescriptor.h"37#include "java_lang_Integer.h"3839#include "jvm.h"40#include "net_util.h"41#include "jni_util.h"4243/************************************************************************44* TwoStacksPlainSocketImpl45*/4647static jfieldID IO_fd_fdID;4849jfieldID psi_fdID;50jfieldID psi_fd1ID;51jfieldID psi_addressID;52jfieldID psi_portID;53jfieldID psi_localportID;54jfieldID psi_timeoutID;55jfieldID psi_trafficClassID;56jfieldID psi_serverSocketID;57jfieldID psi_lastfdID;5859/*60* the level of the TCP protocol for setsockopt and getsockopt61* we only want to look this up once, from the static initializer62* of TwoStacksPlainSocketImpl63*/64static int tcp_level = -1;6566static int getFD(JNIEnv *env, jobject this) {67jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);6869if (fdObj == NULL) {70return -1;71}72return (*env)->GetIntField(env, fdObj, IO_fd_fdID);73}7475static int getFD1(JNIEnv *env, jobject this) {76jobject fdObj = (*env)->GetObjectField(env, this, psi_fd1ID);7778if (fdObj == NULL) {79return -1;80}81return (*env)->GetIntField(env, fdObj, IO_fd_fdID);82}838485/*86* The initProto function is called whenever TwoStacksPlainSocketImpl is87* loaded, to cache fieldIds for efficiency. This is called everytime88* the Java class is loaded.89*90* Class: java_net_TwoStacksPlainSocketImpl91* Method: initProto9293* Signature: ()V94*/95JNIEXPORT void JNICALL96Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) {9798struct protoent *proto = getprotobyname("TCP");99tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto);100101psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;");102CHECK_NULL(psi_fdID);103psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;");104CHECK_NULL(psi_fd1ID);105psi_addressID = (*env)->GetFieldID(env, cls, "address",106"Ljava/net/InetAddress;");107CHECK_NULL(psi_addressID);108psi_portID = (*env)->GetFieldID(env, cls, "port", "I");109CHECK_NULL(psi_portID);110psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");111CHECK_NULL(psi_lastfdID);112psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");113CHECK_NULL(psi_localportID);114psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");115CHECK_NULL(psi_timeoutID);116psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");117CHECK_NULL(psi_trafficClassID);118psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",119"Ljava/net/ServerSocket;");120CHECK_NULL(psi_serverSocketID);121IO_fd_fdID = NET_GetFileDescriptorID(env);122CHECK_NULL(IO_fd_fdID);123}124125/*126* Class: java_net_TwoStacksPlainSocketImpl127* Method: socketCreate128* Signature: (Z)V129*/130JNIEXPORT void JNICALL131Java_java_net_TwoStacksPlainSocketImpl_socketCreate(JNIEnv *env, jobject this,132jboolean stream) {133jobject fdObj, fd1Obj;134int fd, fd1;135136fdObj = (*env)->GetObjectField(env, this, psi_fdID);137138if (IS_NULL(fdObj)) {139JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",140"null fd object");141return;142}143fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);144if (fd == -1) {145NET_ThrowCurrent(env, "create");146return;147} else {148/* Set socket attribute so it is not passed to any child process */149SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);150(*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);151}152if (ipv6_available()) {153fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);154155if (IS_NULL(fd1Obj)) {156(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);157NET_SocketClose(fd);158JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",159"null fd1 object");160return;161}162fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);163if (fd1 == -1) {164(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);165NET_SocketClose(fd);166NET_ThrowCurrent(env, "create");167return;168} else {169/* Set socket attribute so it is not passed to any child process */170SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);171(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);172}173} else {174(*env)->SetObjectField(env, this, psi_fd1ID, NULL);175}176}177178/*179* inetAddress is the address object passed to the socket connect180* call.181*182* Class: java_net_TwoStacksPlainSocketImpl183* Method: socketConnect184* Signature: (Ljava/net/InetAddress;I)V185*/186JNIEXPORT void JNICALL187Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,188jobject iaObj, jint port,189jint timeout)190{191jint localport = (*env)->GetIntField(env, this, psi_localportID);192193/* family and localport are int fields of iaObj */194int family;195jint fd, fd1=-1;196jint len;197int ipv6_supported = ipv6_available();198199/* fd initially points to the IPv4 socket and fd1 to the IPv6 socket200* If we want to connect to IPv6 then we swap the two sockets/objects201* This way, fd is always the connected socket, and fd1 always gets closed.202*/203jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);204jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);205206SOCKETADDRESS him;207208/* The result of the connection */209int connect_res;210memset((char *)&him, 0, sizeof(him));211212if (!IS_NULL(fdObj)) {213fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);214}215216if (ipv6_supported && !IS_NULL(fd1Obj)) {217fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);218}219220if (IS_NULL(iaObj)) {221JNU_ThrowNullPointerException(env, "inet address argument is null.");222return;223}224225if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_FALSE) != 0) {226return;227}228229family = him.him.sa_family;230if (family == AF_INET6) {231if (!ipv6_supported) {232JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",233"Protocol family not supported");234return;235} else {236if (fd1 == -1) {237JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",238"Destination unreachable");239return;240}241/* close the v4 socket, and set fd to be the v6 socket */242(*env)->SetObjectField(env, this, psi_fdID, fd1Obj);243(*env)->SetObjectField(env, this, psi_fd1ID, NULL);244NET_SocketClose(fd);245fd = fd1; fdObj = fd1Obj;246}247} else {248if (fd1 != -1) {249(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);250NET_SocketClose(fd1);251}252if (fd == -1) {253JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",254"Destination unreachable");255return;256}257}258(*env)->SetObjectField(env, this, psi_fd1ID, NULL);259260if (timeout <= 0) {261connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));262if (connect_res == SOCKET_ERROR) {263connect_res = WSAGetLastError();264}265} else {266int optval;267int optlen = sizeof(optval);268269/* make socket non-blocking */270optval = 1;271ioctlsocket( fd, FIONBIO, &optval );272273/* initiate the connect */274connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));275if (connect_res == SOCKET_ERROR) {276if (WSAGetLastError() != WSAEWOULDBLOCK) {277connect_res = WSAGetLastError();278} else {279fd_set wr, ex;280struct timeval t;281282FD_ZERO(&wr);283FD_ZERO(&ex);284FD_SET(fd, &wr);285FD_SET(fd, &ex);286t.tv_sec = timeout / 1000;287t.tv_usec = (timeout % 1000) * 1000;288289/*290* Wait for timout, connection established or291* connection failed.292*/293connect_res = select(fd+1, 0, &wr, &ex, &t);294295/*296* Timeout before connection is established/failed so297* we throw exception and shutdown input/output to prevent298* socket from being used.299* The socket should be closed immediately by the caller.300*/301if (connect_res == 0) {302JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",303"connect timed out");304shutdown( fd, SD_BOTH );305306/* make socket blocking again - just in case */307optval = 0;308ioctlsocket( fd, FIONBIO, &optval );309return;310}311312/*313* We must now determine if the connection has been established314* or if it has failed. The logic here is designed to work around315* bug on Windows NT whereby using getsockopt to obtain the316* last error (SO_ERROR) indicates there is no error. The workaround317* on NT is to allow winsock to be scheduled and this is done by318* yielding and retrying. As yielding is problematic in heavy319* load conditions we attempt up to 3 times to get the error reason.320*/321if (!FD_ISSET(fd, &ex)) {322connect_res = 0;323} else {324int retry;325for (retry=0; retry<3; retry++) {326NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,327(char*)&connect_res, &optlen);328if (connect_res) {329break;330}331Sleep(0);332}333334if (connect_res == 0) {335JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",336"Unable to establish connection");337return;338}339}340}341}342343/* make socket blocking again */344optval = 0;345ioctlsocket(fd, FIONBIO, &optval);346}347348if (connect_res) {349if (connect_res == WSAEADDRNOTAVAIL) {350JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",351"connect: Address is invalid on local machine, or port is not valid on remote machine");352} else {353NET_ThrowNew(env, connect_res, "connect");354}355return;356}357358(*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);359360/* set the remote peer address and port */361(*env)->SetObjectField(env, this, psi_addressID, iaObj);362(*env)->SetIntField(env, this, psi_portID, port);363364/*365* we need to initialize the local port field if bind was called366* previously to the connect (by the client) then localport field367* will already be initialized368*/369if (localport == 0) {370/* Now that we're a connected socket, let's extract the port number371* that the system chose for us and store it in the Socket object.372*/373u_short port;374int len = SOCKETADDRESS_LEN(&him);375if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {376377if (WSAGetLastError() == WSAENOTSOCK) {378JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",379"Socket closed");380} else {381NET_ThrowCurrent(env, "getsockname failed");382}383return;384}385port = ntohs ((u_short)GET_PORT(&him));386(*env)->SetIntField(env, this, psi_localportID, (int) port);387}388}389390/*391* Class: java_net_TwoStacksPlainSocketImpl392* Method: socketBind393* Signature: (Ljava/net/InetAddress;I)V394*/395JNIEXPORT void JNICALL396Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,397jobject iaObj, jint localport,398jboolean exclBind) {399400/* fdObj is the FileDescriptor field on this */401jobject fdObj, fd1Obj;402/* fd is an int field on fdObj */403int fd, fd1, len = 0;404int ipv6_supported = ipv6_available();405406/* family is an int field of iaObj */407int family;408int rv;409410SOCKETADDRESS him;411412fdObj = (*env)->GetObjectField(env, this, psi_fdID);413fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);414415family = getInetAddress_family(env, iaObj);416JNU_CHECK_EXCEPTION(env);417418if (family == IPv6 && !ipv6_supported) {419JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",420"Protocol family not supported");421return;422}423424if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {425JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",426"Socket closed");427return;428} else {429fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);430if (ipv6_supported) {431fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);432}433}434if (IS_NULL(iaObj)) {435JNU_ThrowNullPointerException(env, "inet address argument");436return;437}438439if (NET_InetAddressToSockaddr(env, iaObj, localport,440(struct sockaddr *)&him, &len, JNI_FALSE) != 0) {441return;442}443if (ipv6_supported) {444struct ipv6bind v6bind;445v6bind.addr = &him;446v6bind.ipv4_fd = fd;447v6bind.ipv6_fd = fd1;448rv = NET_BindV6(&v6bind, exclBind);449if (rv != -1) {450/* check if the fds have changed */451if (v6bind.ipv4_fd != fd) {452fd = v6bind.ipv4_fd;453if (fd == -1) {454/* socket is closed. */455(*env)->SetObjectField(env, this, psi_fdID, NULL);456} else {457/* socket was re-created */458(*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);459}460}461if (v6bind.ipv6_fd != fd1) {462fd1 = v6bind.ipv6_fd;463if (fd1 == -1) {464/* socket is closed. */465(*env)->SetObjectField(env, this, psi_fd1ID, NULL);466} else {467/* socket was re-created */468(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);469}470}471} else {472/* NET_BindV6() closes both sockets upon a failure */473(*env)->SetObjectField(env, this, psi_fdID, NULL);474(*env)->SetObjectField(env, this, psi_fd1ID, NULL);475}476} else {477rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind);478}479480if (rv == -1) {481NET_ThrowCurrent(env, "JVM_Bind");482return;483}484485/* set the address */486(*env)->SetObjectField(env, this, psi_addressID, iaObj);487488/* intialize the local port */489if (localport == 0) {490/* Now that we're a bound socket, let's extract the port number491* that the system chose for us and store it in the Socket object.492*/493int len = SOCKETADDRESS_LEN(&him);494u_short port;495fd = him.him.sa_family == AF_INET? fd: fd1;496497if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {498NET_ThrowCurrent(env, "getsockname in plain socketBind");499return;500}501port = ntohs ((u_short) GET_PORT (&him));502503(*env)->SetIntField(env, this, psi_localportID, (int) port);504} else {505(*env)->SetIntField(env, this, psi_localportID, localport);506}507}508509/*510* Class: java_net_TwoStacksPlainSocketImpl511* Method: socketListen512* Signature: (I)V513*/514JNIEXPORT void JNICALL515Java_java_net_TwoStacksPlainSocketImpl_socketListen (JNIEnv *env, jobject this,516jint count)517{518/* this FileDescriptor fd field */519jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);520jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);521jobject address;522/* fdObj's int fd field */523int fd, fd1;524SOCKETADDRESS addr; int addrlen;525526if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {527JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",528"socket closed");529return;530}531532if (!IS_NULL(fdObj)) {533fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);534}535/* Listen on V4 if address type is v4 or if v6 and address is ::0.536* Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0.537* In cases, where we listen on one space only, we close the other socket.538*/539address = (*env)->GetObjectField(env, this, psi_addressID);540if (IS_NULL(address)) {541JNU_ThrowNullPointerException(env, "socket address");542return;543}544if (NET_InetAddressToSockaddr(env, address, 0, (struct sockaddr *)&addr,545&addrlen, JNI_FALSE) != 0) {546return;547}548549if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(&addr.him6)) {550/* listen on v4 */551if (listen(fd, count) == -1) {552NET_ThrowCurrent(env, "listen failed");553}554} else {555NET_SocketClose (fd);556(*env)->SetObjectField(env, this, psi_fdID, NULL);557}558if (ipv6_available() && !IS_NULL(fd1Obj)) {559fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);560if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) {561/* listen on v6 */562if (listen(fd1, count) == -1) {563NET_ThrowCurrent(env, "listen failed");564}565} else {566NET_SocketClose (fd1);567(*env)->SetObjectField(env, this, psi_fd1ID, NULL);568}569}570}571572/*573* Class: java_net_TwoStacksPlainSocketImpl574* Method: socketAccept575* Signature: (Ljava/net/SocketImpl;)V576*/577JNIEXPORT void JNICALL578Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,579jobject socket)580{581/* fields on this */582jint port;583jint scope;584jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);585jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);586jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);587588/* the FileDescriptor field on socket */589jobject socketFdObj;590591/* cache the Inet4/6Address classes */592static jclass inet4Cls;593static jclass inet6Cls;594595/* the InetAddress field on socket */596jobject socketAddressObj;597598/* the fd int field on fdObj */599jint fd=-1, fd1=-1;600601SOCKETADDRESS him;602jint len;603604if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {605JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",606"Socket closed");607return;608}609if (!IS_NULL(fdObj)) {610fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);611}612if (!IS_NULL(fd1Obj)) {613fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);614}615if (IS_NULL(socket)) {616JNU_ThrowNullPointerException(env, "socket is null");617return;618} else {619socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);620socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID);621}622if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) {623JNU_ThrowNullPointerException(env, "socket address or fd obj");624return;625}626if (fd != -1 && fd1 != -1) {627fd_set rfds;628struct timeval t, *tP=&t;629int lastfd, res, fd2;630FD_ZERO(&rfds);631FD_SET(fd,&rfds);632FD_SET(fd1,&rfds);633if (timeout) {634t.tv_sec = timeout/1000;635t.tv_usec = (timeout%1000)*1000;636} else {637tP = NULL;638}639res = select (fd, &rfds, NULL, NULL, tP);640if (res == 0) {641JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",642"Accept timed out");643return;644} else if (res == 1) {645fd2 = FD_ISSET(fd, &rfds)? fd: fd1;646} else if (res == 2) {647/* avoid starvation */648lastfd = (*env)->GetIntField(env, this, psi_lastfdID);649if (lastfd != -1) {650fd2 = lastfd==fd? fd1: fd;651} else {652fd2 = fd;653}654(*env)->SetIntField(env, this, psi_lastfdID, fd2);655} else {656JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",657"select failed");658return;659}660if (fd2 == fd) { /* v4 */661len = sizeof (struct sockaddr_in);662} else {663len = sizeof (struct SOCKADDR_IN6);664}665fd = fd2;666} else {667int ret;668if (fd1 != -1) {669fd = fd1;670len = sizeof (struct SOCKADDR_IN6);671} else {672len = sizeof (struct sockaddr_in);673}674if (timeout) {675ret = NET_Timeout(fd, timeout);676if (ret == 0) {677JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",678"Accept timed out");679return;680} else if (ret == -1) {681JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");682/* REMIND: SOCKET CLOSED PROBLEM */683/* NET_ThrowCurrent(env, "Accept failed"); */684return;685} else if (ret == -2) {686JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",687"operation interrupted");688return;689}690}691}692fd = accept(fd, (struct sockaddr *)&him, &len);693if (fd < 0) {694/* REMIND: SOCKET CLOSED PROBLEM */695if (fd == -2) {696JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",697"operation interrupted");698} else {699JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",700"socket closed");701}702return;703}704SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);705(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);706707if (him.him.sa_family == AF_INET) {708if (inet4Cls == NULL) {709jclass c = (*env)->FindClass(env, "java/net/Inet4Address");710if (c != NULL) {711inet4Cls = (*env)->NewGlobalRef(env, c);712(*env)->DeleteLocalRef(env, c);713}714}715716/*717* fill up the remote peer port and address in the new socket structure718*/719if (inet4Cls != NULL) {720socketAddressObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);721} else {722socketAddressObj = NULL;723}724if (socketAddressObj == NULL) {725/*726* FindClass or NewObject failed so close connection and727* exist (there will be a pending exception).728*/729NET_SocketClose(fd);730return;731}732733setInetAddress_addr(env, socketAddressObj, ntohl(him.him4.sin_addr.s_addr));734JNU_CHECK_EXCEPTION(env);735setInetAddress_family(env, socketAddressObj, IPv4);736JNU_CHECK_EXCEPTION(env);737(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);738} else {739/* AF_INET6 -> Inet6Address */740if (inet6Cls == 0) {741jclass c = (*env)->FindClass(env, "java/net/Inet6Address");742if (c != NULL) {743inet6Cls = (*env)->NewGlobalRef(env, c);744(*env)->DeleteLocalRef(env, c);745}746}747748if (inet6Cls != NULL) {749socketAddressObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);750} else {751socketAddressObj = NULL;752}753if (socketAddressObj == NULL) {754/*755* FindClass or NewObject failed so close connection and756* exist (there will be a pending exception).757*/758NET_SocketClose(fd);759return;760}761setInet6Address_ipaddress(env, socketAddressObj, (const char *)&him.him6.sin6_addr);762setInetAddress_family(env, socketAddressObj, IPv6);763JNU_CHECK_EXCEPTION(env);764setInet6Address_scopeid(env, socketAddressObj, him.him6.sin6_scope_id);765766}767/* fields common to AF_INET and AF_INET6 */768769port = ntohs ((u_short) GET_PORT (&him));770(*env)->SetIntField(env, socket, psi_portID, (int)port);771port = (*env)->GetIntField(env, this, psi_localportID);772(*env)->SetIntField(env, socket, psi_localportID, port);773(*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);774}775776/*777* Class: java_net_TwoStacksPlainSocketImpl778* Method: socketAvailable779* Signature: ()I780*/781JNIEXPORT jint JNICALL782Java_java_net_TwoStacksPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {783784jint available = -1;785jint res;786jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);787jint fd;788789if (IS_NULL(fdObj)) {790JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");791return -1;792} else {793fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);794}795res = ioctlsocket(fd, FIONREAD, &available);796/* if result isn't 0, it means an error */797if (res != 0) {798NET_ThrowNew(env, res, "socket available");799}800return available;801}802803/*804* Class: java_net_TwoStacksPlainSocketImpl805* Method: socketClose806* Signature: ()V807*/808JNIEXPORT void JNICALL809Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,810jboolean useDeferredClose) {811812jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);813jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);814jint fd=-1, fd1=-1;815816if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {817JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",818"socket already closed");819return;820}821if (!IS_NULL(fdObj)) {822fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);823}824if (!IS_NULL(fd1Obj)) {825fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);826}827if (fd != -1) {828(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);829NET_SocketClose(fd);830}831if (fd1 != -1) {832(*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);833NET_SocketClose(fd1);834}835}836837/*838* Socket options for plainsocketImpl839*840*841* Class: java_net_TwoStacksPlainSocketImpl842* Method: socketNativeSetOption843* Signature: (IZLjava/lang/Object;)V844*/845JNIEXPORT void JNICALL846Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption(JNIEnv *env,847jobject this,848jint cmd, jboolean on,849jobject value) {850int fd, fd1;851int level = 0, optname = 0, optlen = 0;852union {853int i;854struct linger ling;855} optval;856857memset((char *)&optval, 0, sizeof(optval));858/*859* Get SOCKET and check that it hasn't been closed860*/861fd = getFD(env, this);862fd1 = getFD1(env, this);863if (fd < 0 && fd1 < 0) {864JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");865return;866}867868/*869* SO_TIMEOUT is the socket option used to specify the timeout870* for ServerSocket.accept and Socket.getInputStream().read.871* It does not typically map to a native level socket option.872* For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO873* socket option to specify a receive timeout on the socket. This874* receive timeout is applicable to Socket only and the socket875* option should not be set on ServerSocket.876*/877if (cmd == java_net_SocketOptions_SO_TIMEOUT) {878879/*880* Don't enable the socket option on ServerSocket as it's881* meaningless (we don't receive on a ServerSocket).882*/883jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);884if (ssObj != NULL) {885return;886}887888/*889* SO_RCVTIMEO is only supported on Microsoft's implementation890* of Windows Sockets so if WSAENOPROTOOPT returned then891* reset flag and timeout will be implemented using892* select() -- see SocketInputStream.socketRead.893*/894if (isRcvTimeoutSupported) {895jclass iCls = (*env)->FindClass(env, "java/lang/Integer");896jfieldID i_valueID;897jint timeout;898899CHECK_NULL(iCls);900i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");901CHECK_NULL(i_valueID);902timeout = (*env)->GetIntField(env, value, i_valueID);903904/*905* Disable SO_RCVTIMEO if timeout is <= 5 second.906*/907if (timeout <= 5000) {908timeout = 0;909}910911if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,912sizeof(timeout)) < 0) {913if (WSAGetLastError() == WSAENOPROTOOPT) {914isRcvTimeoutSupported = JNI_FALSE;915} else {916NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");917return;918}919}920if (fd1 != -1) {921if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,922sizeof(timeout)) < 0) {923NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");924}925}926}927return;928}929930/*931* Map the Java level socket option to the platform specific932* level933*/934if (NET_MapSocketOption(cmd, &level, &optname)) {935JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",936"Invalid option");937return;938}939940switch (cmd) {941942case java_net_SocketOptions_TCP_NODELAY :943case java_net_SocketOptions_SO_OOBINLINE :944case java_net_SocketOptions_SO_KEEPALIVE :945case java_net_SocketOptions_SO_REUSEADDR :946optval.i = (on ? 1 : 0);947optlen = sizeof(optval.i);948break;949950case java_net_SocketOptions_SO_SNDBUF :951case java_net_SocketOptions_SO_RCVBUF :952case java_net_SocketOptions_IP_TOS :953{954jclass cls;955jfieldID fid;956957cls = (*env)->FindClass(env, "java/lang/Integer");958CHECK_NULL(cls);959fid = (*env)->GetFieldID(env, cls, "value", "I");960CHECK_NULL(fid);961962optval.i = (*env)->GetIntField(env, value, fid);963optlen = sizeof(optval.i);964}965break;966967case java_net_SocketOptions_SO_LINGER :968{969jclass cls;970jfieldID fid;971972cls = (*env)->FindClass(env, "java/lang/Integer");973CHECK_NULL(cls);974fid = (*env)->GetFieldID(env, cls, "value", "I");975CHECK_NULL(fid);976977if (on) {978optval.ling.l_onoff = 1;979optval.ling.l_linger =980(unsigned short)(*env)->GetIntField(env, value, fid);981} else {982optval.ling.l_onoff = 0;983optval.ling.l_linger = 0;984}985optlen = sizeof(optval.ling);986}987break;988989default: /* shouldn't get here */990JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",991"Option not supported by TwoStacksPlainSocketImpl");992return;993}994995if (fd != -1) {996if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {997NET_ThrowCurrent(env, "setsockopt");998}999}10001001if (fd1 != -1) {1002if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) {1003NET_ThrowCurrent(env, "setsockopt");1004}1005}1006}100710081009/*1010* Class: java_net_TwoStacksPlainSocketImpl1011* Method: socketGetOption1012* Signature: (I)I1013*/1014JNIEXPORT jint JNICALL1015Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,1016jint opt, jobject iaContainerObj) {10171018int fd, fd1;1019int level = 0, optname = 0, optlen = 0;1020union {1021int i;1022struct linger ling;1023} optval;1024/*1025* Get SOCKET and check it hasn't been closed1026*/1027fd = getFD(env, this);1028fd1 = getFD1(env, this);1029memset((char *)&optval, 0, sizeof(optval));10301031if (fd < 0 && fd1 < 0) {1032JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");1033return -1;1034}1035if (fd < 0) {1036fd = fd1;1037}10381039/* For IPv6, we assume both sockets have the same setting always */10401041/*1042* SO_BINDADDR isn't a socket option1043*/1044if (opt == java_net_SocketOptions_SO_BINDADDR) {1045SOCKETADDRESS him;1046int len;1047int port;1048jobject iaObj;1049jclass iaCntrClass;1050jfieldID iaFieldID;10511052len = sizeof(him);1053memset((char *)&him, 0, len);10541055if (fd == -1) {1056/* must be an IPV6 only socket. Case where both sockets are != -11057* is handled in java1058*/1059fd = getFD1 (env, this);1060}10611062if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {1063NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",1064"Error getting socket name");1065return -1;1066}1067iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);1068CHECK_NULL_RETURN(iaObj, -1);10691070iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);1071iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");1072CHECK_NULL_RETURN(iaFieldID, -1);1073(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);1074return 0; /* notice change from before */1075}10761077/*1078* Map the Java level socket option to the platform specific1079* level and option name.1080*/1081if (NET_MapSocketOption(opt, &level, &optname)) {1082JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");1083return -1;1084}10851086/*1087* Args are int except for SO_LINGER1088*/1089if (opt == java_net_SocketOptions_SO_LINGER) {1090optlen = sizeof(optval.ling);1091} else {1092optlen = sizeof(optval.i);1093optval.i = 0;1094}10951096if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {1097NET_ThrowCurrent(env, "getsockopt");1098return -1;1099}11001101switch (opt) {1102case java_net_SocketOptions_SO_LINGER:1103return (optval.ling.l_onoff ? optval.ling.l_linger: -1);11041105case java_net_SocketOptions_SO_SNDBUF:1106case java_net_SocketOptions_SO_RCVBUF:1107case java_net_SocketOptions_IP_TOS:1108return optval.i;11091110case java_net_SocketOptions_TCP_NODELAY :1111case java_net_SocketOptions_SO_OOBINLINE :1112case java_net_SocketOptions_SO_KEEPALIVE :1113case java_net_SocketOptions_SO_REUSEADDR :1114return (optval.i == 0) ? -1 : 1;11151116default: /* shouldn't get here */1117JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",1118"Option not supported by TwoStacksPlainSocketImpl");1119return -1;1120}1121}11221123/*1124* Class: java_net_TwoStacksPlainSocketImpl1125* Method: socketShutdown1126* Signature: (I)V1127*/1128JNIEXPORT void JNICALL1129Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,1130jint howto)1131{11321133jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);1134jint fd;11351136/*1137* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being1138* -1 already?1139*/1140if (IS_NULL(fdObj)) {1141JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",1142"socket already closed");1143return;1144} else {1145fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);1146}1147shutdown(fd, howto);1148}11491150/*1151* Class: java_net_TwoStacksPlainSocketImpl1152* Method: socketSendUrgentData1153* Signature: (B)V1154*/1155JNIEXPORT void JNICALL1156Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,1157jint data) {1158/* The fd field */1159jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);1160int n, fd;1161unsigned char d = data & 0xff;11621163if (IS_NULL(fdObj)) {1164JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");1165return;1166} else {1167fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);1168/* Bug 4086704 - If the Socket associated with this file descriptor1169* was closed (sysCloseFD), the the file descriptor is set to -1.1170*/1171if (fd == -1) {1172JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");1173return;1174}11751176}1177n = send(fd, (char *)&data, 1, MSG_OOB);1178if (n == JVM_IO_ERR) {1179NET_ThrowCurrent(env, "send");1180return;1181}1182if (n == JVM_IO_INTR) {1183JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);1184return;1185}1186}118711881189