Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/DualStackPlainSocketImpl.c
32287 views
/*1* Copyright (c) 2007, 2013, 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*/24#include <windows.h>25#include <winsock2.h>26#include "jni.h"27#include "net_util.h"28#include "java_net_DualStackPlainSocketImpl.h"2930#define SET_BLOCKING 031#define SET_NONBLOCKING 13233static jclass isa_class; /* java.net.InetSocketAddress */34static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */3536/*37* Class: java_net_DualStackPlainSocketImpl38* Method: initIDs39* Signature: ()V40*/41JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs42(JNIEnv *env, jclass clazz) {4344jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");45CHECK_NULL(cls);46isa_class = (*env)->NewGlobalRef(env, cls);47isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",48"(Ljava/net/InetAddress;I)V");49CHECK_NULL(isa_ctorID);50initInetAddressIDs(env);5152// implement read timeout with select.53isRcvTimeoutSupported = 0;54}5556/*57* Class: java_net_DualStackPlainSocketImpl58* Method: socket059* Signature: (ZZ)I60*/61JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket062(JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {63int fd, rv, opt=0;6465fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);66if (fd == INVALID_SOCKET) {67NET_ThrowNew(env, WSAGetLastError(), "create");68return -1;69}7071rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));72if (rv == SOCKET_ERROR) {73NET_ThrowNew(env, WSAGetLastError(), "create");74}7576SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);7778return fd;79}8081/*82* Class: java_net_DualStackPlainSocketImpl83* Method: bind084* Signature: (ILjava/net/InetAddress;I)V85*/86JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind087(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,88jboolean exclBind)89{90SOCKETADDRESS sa;91int rv;92int sa_len = sizeof(sa);9394if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,95&sa_len, JNI_TRUE) != 0) {96return;97}9899rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);100101if (rv == SOCKET_ERROR)102NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");103}104105/*106* Class: java_net_DualStackPlainSocketImpl107* Method: connect0108* Signature: (ILjava/net/InetAddress;I)I109*/110JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0111(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {112SOCKETADDRESS sa;113int rv;114int sa_len = sizeof(sa);115116if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,117&sa_len, JNI_TRUE) != 0) {118return -1;119}120121rv = connect(fd, (struct sockaddr *)&sa, sa_len);122if (rv == SOCKET_ERROR) {123int err = WSAGetLastError();124if (err == WSAEWOULDBLOCK) {125return java_net_DualStackPlainSocketImpl_WOULDBLOCK;126} else if (err == WSAEADDRNOTAVAIL) {127JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",128"connect: Address is invalid on local machine, or port is not valid on remote machine");129} else {130NET_ThrowNew(env, err, "connect");131}132return -1; // return value not important.133}134return rv;135}136137/*138* Class: java_net_DualStackPlainSocketImpl139* Method: waitForConnect140* Signature: (II)V141*/142JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect143(JNIEnv *env, jclass clazz, jint fd, jint timeout) {144int rv, retry;145int optlen = sizeof(rv);146fd_set wr, ex;147struct timeval t;148149FD_ZERO(&wr);150FD_ZERO(&ex);151FD_SET(fd, &wr);152FD_SET(fd, &ex);153t.tv_sec = timeout / 1000;154t.tv_usec = (timeout % 1000) * 1000;155156/*157* Wait for timeout, connection established or158* connection failed.159*/160rv = select(fd+1, 0, &wr, &ex, &t);161162/*163* Timeout before connection is established/failed so164* we throw exception and shutdown input/output to prevent165* socket from being used.166* The socket should be closed immediately by the caller.167*/168if (rv == 0) {169JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",170"connect timed out");171shutdown( fd, SD_BOTH );172return;173}174175/*176* Socket is writable or error occurred. On some Windows editions177* the socket will appear writable when the connect fails so we178* check for error rather than writable.179*/180if (!FD_ISSET(fd, &ex)) {181return; /* connection established */182}183184/*185* Connection failed. The logic here is designed to work around186* bug on Windows NT whereby using getsockopt to obtain the187* last error (SO_ERROR) indicates there is no error. The workaround188* on NT is to allow winsock to be scheduled and this is done by189* yielding and retrying. As yielding is problematic in heavy190* load conditions we attempt up to 3 times to get the error reason.191*/192for (retry=0; retry<3; retry++) {193NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,194(char*)&rv, &optlen);195if (rv) {196break;197}198Sleep(0);199}200201if (rv == 0) {202JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",203"Unable to establish connection");204} else {205NET_ThrowNew(env, rv, "connect");206}207}208209/*210* Class: java_net_DualStackPlainSocketImpl211* Method: localPort0212* Signature: (I)I213*/214JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0215(JNIEnv *env, jclass clazz, jint fd) {216SOCKETADDRESS sa;217int len = sizeof(sa);218219if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {220if (WSAGetLastError() == WSAENOTSOCK) {221JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",222"Socket closed");223} else {224NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");225}226return -1;227}228return (int) ntohs((u_short)GET_PORT(&sa));229}230231/*232* Class: java_net_DualStackPlainSocketImpl233* Method: localAddress234* Signature: (ILjava/net/InetAddressContainer;)V235*/236JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress237(JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {238int port;239SOCKETADDRESS sa;240int len = sizeof(sa);241jobject iaObj;242jclass iaContainerClass;243jfieldID iaFieldID;244245if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {246NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");247return;248}249iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);250CHECK_NULL(iaObj);251252iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);253iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");254CHECK_NULL(iaFieldID);255(*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);256}257258259/*260* Class: java_net_DualStackPlainSocketImpl261* Method: listen0262* Signature: (II)V263*/264JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0265(JNIEnv *env, jclass clazz, jint fd, jint backlog) {266if (listen(fd, backlog) == SOCKET_ERROR) {267NET_ThrowNew(env, WSAGetLastError(), "listen failed");268}269}270271/*272* Class: java_net_DualStackPlainSocketImpl273* Method: accept0274* Signature: (I[Ljava/net/InetSocketAddress;)I275*/276JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0277(JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {278int newfd, port=0;279jobject isa;280jobject ia;281SOCKETADDRESS sa;282int len = sizeof(sa);283284memset((char *)&sa, 0, len);285newfd = accept(fd, (struct sockaddr *)&sa, &len);286287if (newfd == INVALID_SOCKET) {288if (WSAGetLastError() == -2) {289JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",290"operation interrupted");291} else {292JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",293"socket closed");294}295return -1;296}297298SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);299300ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);301isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);302(*env)->SetObjectArrayElement(env, isaa, 0, isa);303304return newfd;305}306307/*308* Class: java_net_DualStackPlainSocketImpl309* Method: waitForNewConnection310* Signature: (II)V311*/312JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection313(JNIEnv *env, jclass clazz, jint fd, jint timeout) {314int rv;315316rv = NET_Timeout(fd, timeout);317if (rv == 0) {318JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",319"Accept timed out");320} else if (rv == -1) {321JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");322} else if (rv == -2) {323JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",324"operation interrupted");325}326}327328/*329* Class: java_net_DualStackPlainSocketImpl330* Method: available0331* Signature: (I)I332*/333JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0334(JNIEnv *env, jclass clazz, jint fd) {335jint available = -1;336337if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {338NET_ThrowNew(env, WSAGetLastError(), "socket available");339}340341return available;342}343344/*345* Class: java_net_DualStackPlainSocketImpl346* Method: close0347* Signature: (I)V348*/349JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_close0350(JNIEnv *env, jclass clazz, jint fd) {351NET_SocketClose(fd);352}353354/*355* Class: java_net_DualStackPlainSocketImpl356* Method: shutdown0357* Signature: (II)V358*/359JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_shutdown0360(JNIEnv *env, jclass clazz, jint fd, jint howto) {361shutdown(fd, howto);362}363364365/*366* Class: java_net_DualStackPlainSocketImpl367* Method: setIntOption368* Signature: (III)V369*/370JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_setIntOption371(JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) {372373int level = 0, opt = 0;374struct linger linger = {0, 0};375char *parg;376int arglen;377378if (NET_MapSocketOption(cmd, &level, &opt) < 0) {379JNU_ThrowByNameWithLastError(env,380JNU_JAVANETPKG "SocketException",381"Invalid option");382return;383}384385if (opt == java_net_SocketOptions_SO_LINGER) {386parg = (char *)&linger;387arglen = sizeof(linger);388if (value >= 0) {389linger.l_onoff = 1;390linger.l_linger = (unsigned short)value;391} else {392linger.l_onoff = 0;393linger.l_linger = 0;394}395} else {396parg = (char *)&value;397arglen = sizeof(value);398}399400if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {401NET_ThrowNew(env, WSAGetLastError(), "setsockopt");402}403}404405/*406* Class: java_net_DualStackPlainSocketImpl407* Method: getIntOption408* Signature: (II)I409*/410JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption411(JNIEnv *env, jclass clazz, jint fd, jint cmd) {412413int level = 0, opt = 0;414int result=0;415struct linger linger = {0, 0};416char *arg;417int arglen;418419if (NET_MapSocketOption(cmd, &level, &opt) < 0) {420JNU_ThrowByNameWithLastError(env,421JNU_JAVANETPKG "SocketException",422"Unsupported socket option");423return -1;424}425426if (opt == java_net_SocketOptions_SO_LINGER) {427arg = (char *)&linger;428arglen = sizeof(linger);429} else {430arg = (char *)&result;431arglen = sizeof(result);432}433434if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {435NET_ThrowNew(env, WSAGetLastError(), "getsockopt");436return -1;437}438439if (opt == java_net_SocketOptions_SO_LINGER)440return linger.l_onoff ? linger.l_linger : -1;441else442return result;443}444445446/*447* Class: java_net_DualStackPlainSocketImpl448* Method: sendOOB449* Signature: (II)V450*/451JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB452(JNIEnv *env, jclass clazz, jint fd, jint data) {453jint n;454unsigned char d = (unsigned char) data & 0xff;455456n = send(fd, (char *)&data, 1, MSG_OOB);457if (n == JVM_IO_ERR) {458NET_ThrowNew(env, WSAGetLastError(), "send");459} else if (n == JVM_IO_INTR) {460JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);461}462}463464/*465* Class: java_net_DualStackPlainSocketImpl466* Method: configureBlocking467* Signature: (IZ)V468*/469JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking470(JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {471u_long arg;472int result;473474if (blocking == JNI_TRUE) {475arg = SET_BLOCKING; // 0476} else {477arg = SET_NONBLOCKING; // 1478}479480result = ioctlsocket(fd, FIONBIO, &arg);481if (result == SOCKET_ERROR) {482NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");483}484}485486487