Path: blob/master/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c
67760 views
/*1* Copyright (c) 2020, 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>2728#include "jni.h"29#include "jni_util.h"30#include "jvm.h"31#include "jlong.h"32#include "nio.h"33#include "nio_util.h"34#include "net_util.h"3536#include "java_net_InetAddress.h"37#include "sun_nio_ch_Net.h"38#include "sun_nio_ch_PollArrayWrapper.h"3940/* The winsock provider ID of the Microsoft AF_UNIX implementation */41static GUID MS_PROVIDER_ID = {0xA00943D9,0x9C2E,0x4633,{0x9B,0x59,0,0x57,0xA3,0x16,0x09,0x94}};4243jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)44{45if (sa->sun_family == AF_UNIX) {46int namelen = (int)strlen(sa->sun_path);47jbyteArray name = (*env)->NewByteArray(env, namelen);48if (name != NULL) {49(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);50if ((*env)->ExceptionOccurred(env)) {51return NULL;52}53}54return name;55}56return NULL;57}5859jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray addr, struct sockaddr_un *sa, int *len)60{61memset(sa, 0, sizeof(struct sockaddr_un));62sa->sun_family = AF_UNIX;63if (addr == 0L) {64/* Do explicit bind on Windows */65*len = (int)(offsetof(struct sockaddr_un, sun_path));66return 0;67}68int ret;69jboolean isCopy;70char *pname = (*env)->GetByteArrayElements(env, addr, &isCopy);71if (pname == NULL) {72JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");73return -1;74}7576size_t name_len = (size_t)(*env)->GetArrayLength(env, addr);77if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {78JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");79ret = -1;80} else {81strncpy(sa->sun_path, pname, name_len);82*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);83ret = 0;84}85(*env)->ReleaseByteArrayElements(env, addr, pname, JNI_ABORT);86return ret;87}8889static int cmpGuid(GUID *g1, GUID *g2) {90if (g1->Data1 != g2->Data1)91return JNI_FALSE;92if (g1->Data2 != g2->Data2)93return JNI_FALSE;94if (g1->Data3 != g2->Data3)95return JNI_FALSE;96for (int i=0; i<8; i++) {97if (g1->Data4[i] != g2->Data4[i])98return JNI_FALSE;99}100return JNI_TRUE;101}102103static WSAPROTOCOL_INFOW provider;104105JNIEXPORT jboolean JNICALL106Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv *env, jclass cl)107{108WSAPROTOCOL_INFOW info[5]; // if not large enough, a buffer is malloc'd109LPWSAPROTOCOL_INFOW infoPtr = &info[0];110DWORD len = sizeof(info);111jboolean found = JNI_FALSE;112113/*114* First locate the Microsoft AF_UNIX Winsock provider115*/116int result = WSAEnumProtocolsW(0, infoPtr, &len);117if (result == SOCKET_ERROR) {118if (GetLastError() == WSAENOBUFS) {119infoPtr = (LPWSAPROTOCOL_INFOW)malloc(len);120result = WSAEnumProtocolsW(0, infoPtr, &len);121if (result == SOCKET_ERROR) {122free(infoPtr);123return JNI_FALSE;124}125} else {126return JNI_FALSE;127}128}129for (int i=0; i<result; i++) {130if (infoPtr[i].iAddressFamily == AF_UNIX) {131GUID g = infoPtr[i].ProviderId;132if (cmpGuid(&g, &MS_PROVIDER_ID)) {133found = JNI_TRUE;134provider = infoPtr[i];135break;136}137}138}139if (infoPtr != &info[0]) {140free(infoPtr);141}142/*143* check we can create a socket144*/145if (found) {146SOCKET s = WSASocketW(PF_UNIX, SOCK_STREAM, 0, &provider, 0, WSA_FLAG_OVERLAPPED);147if (s == INVALID_SOCKET) {148return JNI_FALSE;149}150closesocket(s);151}152return found;153}154155JNIEXPORT jint JNICALL156Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)157{158SOCKET s = WSASocketW(PF_UNIX, SOCK_STREAM, 0, &provider, 0, WSA_FLAG_OVERLAPPED);159if (s == INVALID_SOCKET) {160return handleSocketError(env, WSAGetLastError());161}162SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);163return (int)s;164}165166/**167* Windows does not support auto bind. So, the windows version of unixSocketAddressToSockaddr168* looks out for a null 'uaddr' and handles it specially169*/170JNIEXPORT void JNICALL171Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)172{173struct sockaddr_un sa;174int sa_len = 0;175int rv = 0;176177if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0)178return;179180rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);181if (rv == SOCKET_ERROR) {182int err = WSAGetLastError();183NET_ThrowNew(env, err, "bind");184}185}186187JNIEXPORT jint JNICALL188Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)189{190struct sockaddr_un sa;191int sa_len = 0;192int rv;193194if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) {195return IOS_THROWN;196}197198rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len);199if (rv != 0) {200int err = WSAGetLastError();201if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {202return IOS_UNAVAILABLE;203}204NET_ThrowNew(env, err, "connect");205return IOS_THROWN;206}207return 1;208}209210JNIEXPORT jint JNICALL211Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,212jobjectArray array)213{214jint fd = fdval(env, fdo);215jint newfd;216struct sockaddr_un sa;217socklen_t sa_len = sizeof(sa);218jbyteArray address;219220memset((char *)&sa, 0, sizeof(sa));221newfd = (jint) accept(fd, (struct sockaddr *)&sa, &sa_len);222if (newfd == INVALID_SOCKET) {223int theErr = (jint)WSAGetLastError();224if (theErr == WSAEWOULDBLOCK) {225return IOS_UNAVAILABLE;226}227JNU_ThrowIOExceptionWithLastError(env, "Accept failed");228return IOS_THROWN;229}230231SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);232setfdval(env, newfdo, newfd);233234address = sockaddrToUnixAddressBytes(env, &sa, sa_len);235CHECK_NULL_RETURN(address, IOS_THROWN);236(*env)->SetObjectArrayElement(env, array, 0, address);237238return 1;239}240241JNIEXPORT jbyteArray JNICALL242Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)243{244struct sockaddr_un sa;245int sa_len = sizeof(sa);246247if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) == SOCKET_ERROR) {248JNU_ThrowIOExceptionWithLastError(env, "getsockname");249return NULL;250}251return sockaddrToUnixAddressBytes(env, &sa, sa_len);252}253254255256