1 /*
   2  * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <windows.h>
  27 #include <winsock2.h>
  28 
  29 #include "jni.h"
  30 #include "jni_util.h"
  31 #include "jvm.h"
  32 #include "jlong.h"
  33 #include "nio.h"
  34 #include "nio_util.h"
  35 #include "net_util.h"
  36 
  37 #include "java_net_InetAddress.h"
  38 #include "sun_nio_ch_Net.h"
  39 #include "sun_nio_ch_PollArrayWrapper.h"
  40 
  41 JNIEXPORT jobject JNICALL
  42 NET_SockaddrToUnixAddressString(JNIEnv *env, struct sockaddr_un *sa, socklen_t len) {
  43 
  44     if (sa->sun_family == AF_UNIX) {
  45         return JNU_NewStringPlatform(env, sa->sun_path);
  46     }
  47     return NULL;
  48 }
  49 
  50 JNIEXPORT jint JNICALL
  51 NET_UnixSocketAddressToSockaddr(JNIEnv *env, jbyteArray addr, struct sockaddr_un *sa, int *len)
  52 {
  53     memset(sa, 0, sizeof(struct sockaddr_un));
  54     sa->sun_family = AF_UNIX;
  55     if (addr == 0L) {
  56         /* Do explicit bind on Windows */
  57         *len = (int)(offsetof(struct sockaddr_un, sun_path));
  58         return 0;
  59     }
  60     int ret;
  61     jboolean isCopy;
  62     char *pname = (*env)->GetByteArrayElements(env, addr, &isCopy);
  63 
  64     size_t name_len = (size_t)(*env)->GetArrayLength(env, addr);
  65     if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
  66         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
  67         ret=1;
  68         goto finish;
  69     }
  70     strncpy(sa->sun_path, pname, name_len);
  71     *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);
  72     ret = 0;
  73   finish:
  74     (*env)->ReleaseByteArrayElements(env, addr, pname, JNI_ABORT);
  75     return ret;
  76 }
  77 
  78 
  79 JNIEXPORT jboolean JNICALL
  80 Java_sun_nio_ch_UnixDomainNet_socketSupported(JNIEnv *env, jclass cl)
  81 {
  82     SOCKET fd = socket(PF_UNIX, SOCK_STREAM, 0);
  83     if (fd == INVALID_SOCKET) {
  84         return JNI_FALSE;
  85     }
  86     closesocket(fd);
  87     return JNI_TRUE;
  88 }
  89 
  90 JNIEXPORT jint JNICALL
  91 Java_sun_nio_ch_UnixDomainNet_maxNameLen0(JNIEnv *env, jclass cl)
  92 {
  93     return MAX_UNIX_DOMAIN_PATH_LEN - 1;
  94 }
  95 
  96 JNIEXPORT jint JNICALL
  97 Java_sun_nio_ch_UnixDomainNet_socket0(JNIEnv *env, jclass cl)
  98 {
  99     SOCKET fd = socket(PF_UNIX, SOCK_STREAM, 0);
 100     if (fd == INVALID_SOCKET) {
 101         return handleSocketError(env, WSAGetLastError());
 102     }
 103     return (int)fd;
 104 }
 105 
 106 /**
 107  * Windows does not support auto bind. So, the windows version of NET_UnixSocketAddressToSockaddr
 108  * looks out for a null 'uaddr' and handles it specially
 109  */
 110 JNIEXPORT void JNICALL
 111 Java_sun_nio_ch_UnixDomainNet_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
 112 {
 113     struct sockaddr_un sa;
 114     int sa_len = 0;
 115     int rv = 0;
 116 
 117     if (NET_UnixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0)
 118         return;
 119 
 120     int fd = fdval(env, fdo);
 121 
 122     rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
 123     if (rv != 0) {
 124         int err = WSAGetLastError();
 125         NET_ThrowNew(env, err, "bind");
 126     }
 127 }
 128 
 129 JNIEXPORT jint JNICALL
 130 Java_sun_nio_ch_UnixDomainNet_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
 131 {
 132     struct sockaddr_un sa;
 133     int sa_len = 0;
 134     int rv;
 135 
 136     if (NET_UnixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) {
 137         return IOS_THROWN;
 138     }
 139 
 140     rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len);
 141     if (rv != 0) {
 142         int err = WSAGetLastError();
 143         if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
 144             return IOS_UNAVAILABLE;
 145         }
 146         NET_ThrowNew(env, err, "connect");
 147         return IOS_THROWN;
 148     }
 149     return 1;
 150 }
 151 
 152 JNIEXPORT jint JNICALL
 153 Java_sun_nio_ch_UnixDomainNet_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
 154                            jobjectArray usaa)
 155 {
 156     jint fd = fdval(env, fdo);
 157     jint newfd;
 158     struct sockaddr_un sa;
 159     socklen_t sa_len = sizeof(sa);
 160     jobject usa;
 161 
 162     memset((char *)&sa, 0, sizeof(sa));
 163     newfd = (jint) accept(fd, (struct sockaddr *)&sa, &sa_len);
 164     if (newfd == INVALID_SOCKET) {
 165         int theErr = (jint)WSAGetLastError();
 166         if (theErr == WSAEWOULDBLOCK) {
 167             return IOS_UNAVAILABLE;
 168         }
 169         JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
 170         return IOS_THROWN;
 171     }
 172 
 173     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 174     setfdval(env, newfdo, newfd);
 175 
 176     usa = NET_SockaddrToUnixAddressString(env, &sa, sa_len);
 177     CHECK_NULL_RETURN(usa, IOS_THROWN);
 178 
 179     (*env)->SetObjectArrayElement(env, usaa, 0, usa);
 180 
 181     return 1;
 182 }
 183 
 184 /* only used here so as not to make SOCKETADDRESS too large
 185  * and some buggy usages elsewhere
 186  */
 187 typedef union {
 188     struct sockaddr     sa;
 189     struct sockaddr_in  sa4;
 190     struct sockaddr_in6 sa6;
 191     struct sockaddr_un  saun;
 192 } sockaddrall;
 193 
 194 JNIEXPORT jobject JNICALL
 195 Java_sun_nio_ch_UnixDomainNet_localAddress(JNIEnv *env, jclass clazz, jobject fdo)
 196 {
 197     sockaddrall sa;
 198     int sa_len = sizeof(sa);
 199 
 200     if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) {
 201         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
 202         return NULL;
 203     }
 204     return NET_SockaddrToUnixAddressString(env, &sa.saun, sa_len);
 205 }
 206 
 207 JNIEXPORT jobject JNICALL
 208 Java_sun_nio_ch_UnixDomainNet_remoteAddress(JNIEnv *env, jclass clazz, jobject fdo)
 209 {
 210     sockaddrall sa;
 211     int sa_len = sizeof(sa);
 212 
 213     if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) {
 214         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
 215         return NULL;
 216     }
 217     return NET_SockaddrToUnixAddressString(env, &sa.saun, sa_len);
 218 }