1 /* 2 * Copyright (c) 2007, 2016, 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 #include <windows.h> 26 #include <winsock2.h> 27 #include "jni.h" 28 #include "net_util.h" 29 #include "java_net_DualStackPlainSocketImpl.h" 30 31 #define SET_BLOCKING 0 32 #define SET_NONBLOCKING 1 33 34 static jclass isa_class; /* java.net.InetSocketAddress */ 35 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ 36 37 /* 38 * Class: java_net_DualStackPlainSocketImpl 39 * Method: initIDs 40 * Signature: ()V 41 */ 42 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs 43 (JNIEnv *env, jclass clazz) { 44 45 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 46 CHECK_NULL(cls); 47 isa_class = (*env)->NewGlobalRef(env, cls); 48 CHECK_NULL(isa_class); 49 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", 50 "(Ljava/net/InetAddress;I)V"); 51 CHECK_NULL(isa_ctorID); 52 initInetAddressIDs(env); 53 54 // implement read timeout with select. 55 isRcvTimeoutSupported = 0; 56 } 57 58 /* 59 * Class: java_net_DualStackPlainSocketImpl 60 * Method: socket0 61 * Signature: (ZZ)I 62 */ 63 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 64 (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) { 65 int fd, rv, opt=0; 66 67 fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); 68 if (fd == INVALID_SOCKET) { 69 NET_ThrowNew(env, WSAGetLastError(), "create"); 70 return -1; 71 } 72 73 rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt)); 74 if (rv == SOCKET_ERROR) { 75 NET_ThrowNew(env, WSAGetLastError(), "create"); 76 } 77 78 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 79 80 return fd; 81 } 82 83 /* 84 * Class: java_net_DualStackPlainSocketImpl 85 * Method: bind0 86 * Signature: (ILjava/net/InetAddress;I)V 87 */ 88 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0 89 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, 90 jboolean exclBind) 91 { 92 SOCKETADDRESS sa; 93 int rv; 94 int sa_len = sizeof(sa); 95 96 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, 97 &sa_len, JNI_TRUE) != 0) { 98 return; 99 } 100 101 rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind); 102 103 if (rv == SOCKET_ERROR) 104 NET_ThrowNew(env, WSAGetLastError(), "NET_Bind"); 105 } 106 107 /* 108 * Class: java_net_DualStackPlainSocketImpl 109 * Method: connect0 110 * Signature: (ILjava/net/InetAddress;I)I 111 */ 112 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 113 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { 114 SOCKETADDRESS sa; 115 int rv; 116 int sa_len = sizeof(sa); 117 118 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, 119 &sa_len, JNI_TRUE) != 0) { 120 return -1; 121 } 122 123 rv = connect(fd, (struct sockaddr *)&sa, sa_len); 124 if (rv == SOCKET_ERROR) { 125 int err = WSAGetLastError(); 126 if (err == WSAEWOULDBLOCK) { 127 return java_net_DualStackPlainSocketImpl_WOULDBLOCK; 128 } else if (err == WSAEADDRNOTAVAIL) { 129 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 130 "connect: Address is invalid on local machine, or port is not valid on remote machine"); 131 } else { 132 NET_ThrowNew(env, err, "connect"); 133 } 134 return -1; // return value not important. 135 } 136 return rv; 137 } 138 139 /* 140 * Class: java_net_DualStackPlainSocketImpl 141 * Method: waitForConnect 142 * Signature: (II)V 143 */ 144 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect 145 (JNIEnv *env, jclass clazz, jint fd, jint timeout) { 146 int rv, retry; 147 int optlen = sizeof(rv); 148 fd_set wr, ex; 149 struct timeval t; 150 151 FD_ZERO(&wr); 152 FD_ZERO(&ex); 153 FD_SET(fd, &wr); 154 FD_SET(fd, &ex); 155 t.tv_sec = timeout / 1000; 156 t.tv_usec = (timeout % 1000) * 1000; 157 158 /* 159 * Wait for timeout, connection established or 160 * connection failed. 161 */ 162 rv = select(fd+1, 0, &wr, &ex, &t); 163 164 /* 165 * Timeout before connection is established/failed so 166 * we throw exception and shutdown input/output to prevent 167 * socket from being used. 168 * The socket should be closed immediately by the caller. 169 */ 170 if (rv == 0) { 171 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 172 "connect timed out"); 173 shutdown( fd, SD_BOTH ); 174 return; 175 } 176 177 /* 178 * Socket is writable or error occurred. On some Windows editions 179 * the socket will appear writable when the connect fails so we 180 * check for error rather than writable. 181 */ 182 if (!FD_ISSET(fd, &ex)) { 183 return; /* connection established */ 184 } 185 186 /* 187 * Connection failed. The logic here is designed to work around 188 * bug on Windows NT whereby using getsockopt to obtain the 189 * last error (SO_ERROR) indicates there is no error. The workaround 190 * on NT is to allow winsock to be scheduled and this is done by 191 * yielding and retrying. As yielding is problematic in heavy 192 * load conditions we attempt up to 3 times to get the error reason. 193 */ 194 for (retry=0; retry<3; retry++) { 195 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, 196 (char*)&rv, &optlen); 197 if (rv) { 198 break; 199 } 200 Sleep(0); 201 } 202 203 if (rv == 0) { 204 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 205 "Unable to establish connection"); 206 } else { 207 NET_ThrowNew(env, rv, "connect"); 208 } 209 } 210 211 /* 212 * Class: java_net_DualStackPlainSocketImpl 213 * Method: localPort0 214 * Signature: (I)I 215 */ 216 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0 217 (JNIEnv *env, jclass clazz, jint fd) { 218 SOCKETADDRESS sa; 219 int len = sizeof(sa); 220 221 if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { 222 if (WSAGetLastError() == WSAENOTSOCK) { 223 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 224 "Socket closed"); 225 } else { 226 NET_ThrowNew(env, WSAGetLastError(), "getsockname failed"); 227 } 228 return -1; 229 } 230 return (int) ntohs((u_short)GET_PORT(&sa)); 231 } 232 233 /* 234 * Class: java_net_DualStackPlainSocketImpl 235 * Method: localAddress 236 * Signature: (ILjava/net/InetAddressContainer;)V 237 */ 238 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress 239 (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) { 240 int port; 241 SOCKETADDRESS sa; 242 int len = sizeof(sa); 243 jobject iaObj; 244 jclass iaContainerClass; 245 jfieldID iaFieldID; 246 247 if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { 248 NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); 249 return; 250 } 251 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); 252 CHECK_NULL(iaObj); 253 254 iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj); 255 iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;"); 256 CHECK_NULL(iaFieldID); 257 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 258 } 259 260 261 /* 262 * Class: java_net_DualStackPlainSocketImpl 263 * Method: listen0 264 * Signature: (II)V 265 */ 266 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0 267 (JNIEnv *env, jclass clazz, jint fd, jint backlog) { 268 if (listen(fd, backlog) == SOCKET_ERROR) { 269 NET_ThrowNew(env, WSAGetLastError(), "listen failed"); 270 } 271 } 272 273 /* 274 * Class: java_net_DualStackPlainSocketImpl 275 * Method: accept0 276 * Signature: (I[Ljava/net/InetSocketAddress;)I 277 */ 278 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0 279 (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) { 280 int newfd, port=0; 281 jobject isa; 282 jobject ia; 283 SOCKETADDRESS sa; 284 int len = sizeof(sa); 285 286 memset((char *)&sa, 0, len); 287 newfd = accept(fd, (struct sockaddr *)&sa, &len); 288 289 if (newfd == INVALID_SOCKET) { 290 if (WSAGetLastError() == -2) { 291 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 292 "operation interrupted"); 293 } else { 294 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 295 "socket closed"); 296 } 297 return -1; 298 } 299 300 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); 301 302 ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); 303 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); 304 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 305 306 return newfd; 307 } 308 309 /* 310 * Class: java_net_DualStackPlainSocketImpl 311 * Method: waitForNewConnection 312 * Signature: (II)V 313 */ 314 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection 315 (JNIEnv *env, jclass clazz, jint fd, jint timeout) { 316 int rv; 317 318 rv = NET_Timeout(fd, timeout); 319 if (rv == 0) { 320 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 321 "Accept timed out"); 322 } else if (rv == -1) { 323 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 324 } else if (rv == -2) { 325 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 326 "operation interrupted"); 327 } 328 } 329 330 /* 331 * Class: java_net_DualStackPlainSocketImpl 332 * Method: available0 333 * Signature: (I)I 334 */ 335 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0 336 (JNIEnv *env, jclass clazz, jint fd) { 337 jint available = -1; 338 339 if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) { 340 NET_ThrowNew(env, WSAGetLastError(), "socket available"); 341 } 342 343 return available; 344 } 345 346 /* 347 * Class: java_net_DualStackPlainSocketImpl 348 * Method: close0 349 * Signature: (I)V 350 */ 351 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_close0 352 (JNIEnv *env, jclass clazz, jint fd) { 353 NET_SocketClose(fd); 354 } 355 356 /* 357 * Class: java_net_DualStackPlainSocketImpl 358 * Method: shutdown0 359 * Signature: (II)V 360 */ 361 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_shutdown0 362 (JNIEnv *env, jclass clazz, jint fd, jint howto) { 363 shutdown(fd, howto); 364 } 365 366 367 /* 368 * Class: java_net_DualStackPlainSocketImpl 369 * Method: setIntOption 370 * Signature: (III)V 371 */ 372 JNIEXPORT void JNICALL 373 Java_java_net_DualStackPlainSocketImpl_setIntOption 374 (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) 375 { 376 int level = 0, opt = 0; 377 struct linger linger = {0, 0}; 378 char *parg; 379 int arglen; 380 381 if (NET_MapSocketOption(cmd, &level, &opt) < 0) { 382 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 383 return; 384 } 385 386 if (opt == java_net_SocketOptions_SO_LINGER) { 387 parg = (char *)&linger; 388 arglen = sizeof(linger); 389 if (value >= 0) { 390 linger.l_onoff = 1; 391 linger.l_linger = (unsigned short)value; 392 } else { 393 linger.l_onoff = 0; 394 linger.l_linger = 0; 395 } 396 } else { 397 parg = (char *)&value; 398 arglen = sizeof(value); 399 } 400 401 if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) { 402 NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); 403 } 404 } 405 406 /* 407 * Class: java_net_DualStackPlainSocketImpl 408 * Method: getIntOption 409 * Signature: (II)I 410 */ 411 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption 412 (JNIEnv *env, jclass clazz, jint fd, jint cmd) 413 { 414 int level = 0, opt = 0; 415 int result=0; 416 struct linger linger = {0, 0}; 417 char *arg; 418 int arglen; 419 420 if (NET_MapSocketOption(cmd, &level, &opt) < 0) { 421 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 422 return -1; 423 } 424 425 if (opt == java_net_SocketOptions_SO_LINGER) { 426 arg = (char *)&linger; 427 arglen = sizeof(linger); 428 } else { 429 arg = (char *)&result; 430 arglen = sizeof(result); 431 } 432 433 if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) { 434 NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); 435 return -1; 436 } 437 438 if (opt == java_net_SocketOptions_SO_LINGER) 439 return linger.l_onoff ? linger.l_linger : -1; 440 else 441 return result; 442 } 443 444 445 /* 446 * Class: java_net_DualStackPlainSocketImpl 447 * Method: sendOOB 448 * Signature: (II)V 449 */ 450 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB 451 (JNIEnv *env, jclass clazz, jint fd, jint data) { 452 jint n; 453 unsigned char d = (unsigned char) data & 0xff; 454 455 n = send(fd, (char *)&data, 1, MSG_OOB); 456 if (n == SOCKET_ERROR) { 457 NET_ThrowNew(env, WSAGetLastError(), "send"); 458 } 459 } 460 461 /* 462 * Class: java_net_DualStackPlainSocketImpl 463 * Method: configureBlocking 464 * Signature: (IZ)V 465 */ 466 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking 467 (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) { 468 u_long arg; 469 int result; 470 471 if (blocking == JNI_TRUE) { 472 arg = SET_BLOCKING; // 0 473 } else { 474 arg = SET_NONBLOCKING; // 1 475 } 476 477 result = ioctlsocket(fd, FIONBIO, &arg); 478 if (result == SOCKET_ERROR) { 479 NET_ThrowNew(env, WSAGetLastError(), "configureBlocking"); 480 } 481 }