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 }