1 /* 2 * Copyright (c) 1997, 2018, 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 "net_util.h" 26 27 #include "java_net_TwoStacksPlainSocketImpl.h" 28 #include "java_net_SocketOptions.h" 29 #include "java_net_InetAddress.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 * TwoStacksPlainSocketImpl 39 */ 40 41 /* 42 * The initIDs function is called whenever TwoStacksPlainSocketImpl is 43 * loaded, to cache fieldIds for efficiency. This is called everytime 44 * the Java class is loaded. 45 * 46 * Class: java_net_TwoStacksPlainSocketImpl 47 * Method: initIDs 48 * Signature: ()V 49 */ 50 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_initIDs 51 (JNIEnv *env, jclass clazz) { 52 53 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 54 CHECK_NULL(cls); 55 isa_class = (*env)->NewGlobalRef(env, cls); 56 CHECK_NULL(isa_class); 57 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", 58 "(Ljava/net/InetAddress;I)V"); 59 CHECK_NULL(isa_ctorID); 60 } 61 62 /* 63 * Class: java_net_TwoStacksPlainSocketImpl 64 * Method: socket0 65 * Signature: (ZZ)I 66 */ 67 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_socket0 68 (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) { 69 int fd; 70 71 fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); 72 if (fd == INVALID_SOCKET) { 73 NET_ThrowNew(env, WSAGetLastError(), "create"); 74 return -1; 75 } 76 77 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 78 79 return fd; 80 } 81 82 /* 83 * Class: java_net_TwoStacksPlainSocketImpl 84 * Method: bind0 85 * Signature: (ILjava/net/InetAddress;I)V 86 */ 87 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_bind0 88 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, 89 jboolean exclBind) 90 { 91 SOCKETADDRESS sa; 92 int rv, sa_len = 0; 93 /* family is an int field of iaObj */ 94 int family; 95 96 family = getInetAddress_family(env, iaObj); 97 if (family != java_net_InetAddress_IPv4) { 98 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 99 "Protocol family not supported"); 100 return; 101 } 102 103 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, 104 &sa_len, JNI_FALSE) != 0) { 105 return; 106 } 107 108 rv = NET_WinBind(fd, &sa, sa_len, exclBind); 109 110 if (rv == SOCKET_ERROR) 111 NET_ThrowNew(env, WSAGetLastError(), "NET_Bind"); 112 } 113 114 /* 115 * Class: java_net_TwoStacksPlainSocketImpl 116 * Method: connect0 117 * Signature: (ILjava/net/InetAddress;I)I 118 */ 119 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_connect0 120 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { 121 SOCKETADDRESS sa; 122 int rv, sa_len = 0; 123 int family; 124 125 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, 126 &sa_len, JNI_FALSE) != 0) { 127 return -1; 128 } 129 130 family = sa.sa.sa_family; 131 if (family != AF_INET) { 132 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 133 "Protocol family not supported"); 134 return -1; 135 } 136 137 rv = connect(fd, &sa.sa, sa_len); 138 if (rv == SOCKET_ERROR) { 139 int err = WSAGetLastError(); 140 if (err == WSAEWOULDBLOCK) { 141 return java_net_TwoStacksPlainSocketImpl_WOULDBLOCK; 142 } else if (err == WSAEADDRNOTAVAIL) { 143 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 144 "connect: Address is invalid on local machine, or port is not valid on remote machine"); 145 } else { 146 NET_ThrowNew(env, err, "connect"); 147 } 148 return -1; // return value not important. 149 } 150 return rv; 151 } 152 153 /* 154 * Class: java_net_TwoStacksPlainSocketImpl 155 * Method: waitForConnect 156 * Signature: (II)V 157 */ 158 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForConnect 159 (JNIEnv *env, jclass clazz, jint fd, jint timeout) { 160 int rv, retry; 161 int optlen = sizeof(rv); 162 fd_set wr, ex; 163 struct timeval t; 164 165 FD_ZERO(&wr); 166 FD_ZERO(&ex); 167 FD_SET(fd, &wr); 168 FD_SET(fd, &ex); 169 t.tv_sec = timeout / 1000; 170 t.tv_usec = (timeout % 1000) * 1000; 171 172 /* 173 * Wait for timeout, connection established or 174 * connection failed. 175 */ 176 rv = select(fd+1, 0, &wr, &ex, &t); 177 178 /* 179 * Timeout before connection is established/failed so 180 * we throw exception and shutdown input/output to prevent 181 * socket from being used. 182 * The socket should be closed immediately by the caller. 183 */ 184 if (rv == 0) { 185 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 186 "connect timed out"); 187 shutdown( fd, SD_BOTH ); 188 return; 189 } 190 /* 191 * Socket is writable or error occurred. On some Windows editions 192 * the socket will appear writable when the connect fails so we 193 * check for error rather than writable. 194 */ 195 if (!FD_ISSET(fd, &ex)) { 196 return; /* connection established */ 197 } 198 199 /* 200 * Connection failed. The logic here is designed to work around 201 * bug on Windows NT whereby using getsockopt to obtain the 202 * last error (SO_ERROR) indicates there is no error. The workaround 203 * on NT is to allow winsock to be scheduled and this is done by 204 * yielding and retrying. As yielding is problematic in heavy 205 * load conditions we attempt up to 3 times to get the error reason. 206 */ 207 for (retry=0; retry<3; retry++) { 208 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, 209 (char*)&rv, &optlen); 210 if (rv) { 211 break; 212 } 213 Sleep(0); 214 } 215 216 if (rv == 0) { 217 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 218 "Unable to establish connection"); 219 } else if (rv == WSAEADDRNOTAVAIL) { 220 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 221 "connect: Address is invalid on local machine," 222 " or port is not valid on remote machine"); 223 } else { 224 NET_ThrowNew(env, rv, "connect"); 225 } 226 } 227 228 /* 229 * Class: java_net_TwoStacksPlainSocketImpl 230 * Method: localPort0 231 * Signature: (I)I 232 */ 233 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_localPort0 234 (JNIEnv *env, jclass clazz, jint fd) { 235 SOCKETADDRESS sa; 236 int len = sizeof(sa); 237 238 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { 239 if (WSAGetLastError() == WSAENOTSOCK) { 240 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 241 "Socket closed"); 242 } else { 243 NET_ThrowNew(env, WSAGetLastError(), "getsockname failed"); 244 } 245 return -1; 246 } 247 return (int) ntohs((u_short)GET_PORT(&sa)); 248 } 249 250 /* 251 * Class: java_net_TwoStacksPlainSocketImpl 252 * Method: localAddress 253 * Signature: (ILjava/net/InetAddressContainer;)V 254 */ 255 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_localAddress 256 (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) { 257 int port; 258 SOCKETADDRESS sa; 259 int len = sizeof(sa); 260 jobject iaObj; 261 jclass iaContainerClass; 262 jfieldID iaFieldID; 263 264 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { 265 NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); 266 return; 267 } 268 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 269 CHECK_NULL(iaObj); 270 271 iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj); 272 iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;"); 273 CHECK_NULL(iaFieldID); 274 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 275 } 276 277 278 /* 279 * Class: java_net_TwoStacksPlainSocketImpl 280 * Method: listen0 281 * Signature: (II)V 282 */ 283 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_listen0 284 (JNIEnv *env, jclass clazz, jint fd, jint backlog) { 285 if (listen(fd, backlog) == SOCKET_ERROR) { 286 NET_ThrowNew(env, WSAGetLastError(), "listen failed"); 287 } 288 } 289 290 /* 291 * Class: java_net_TwoStacksPlainSocketImpl 292 * Method: accept0 293 * Signature: (I[Ljava/net/InetSocketAddress;)I 294 */ 295 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_accept0 296 (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) { 297 int newfd, port=0; 298 jobject isa; 299 jobject ia; 300 SOCKETADDRESS sa; 301 int len = sizeof(sa); 302 303 memset((char *)&sa, 0, len); 304 newfd = accept(fd, &sa.sa, &len); 305 306 if (newfd < 0) { 307 if (newfd == -2) { 308 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 309 "operation interrupted"); 310 } else { 311 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 312 "socket closed"); 313 } 314 return -1; 315 } 316 317 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); 318 319 if (sa.sa.sa_family != AF_INET) { 320 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 321 "Protocol family not supported"); 322 NET_SocketClose(newfd); 323 return -1; 324 } 325 326 ia = NET_SockaddrToInetAddress(env, &sa, &port); 327 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); 328 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 329 330 return newfd; 331 } 332 333 /* 334 * Class: java_net_TwoStacksPlainSocketImpl 335 * Method: waitForNewConnection 336 * Signature: (II)V 337 */ 338 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForNewConnection 339 (JNIEnv *env, jclass clazz, jint fd, jint timeout) { 340 int rv; 341 342 rv = NET_Timeout(fd, timeout); 343 if (rv == 0) { 344 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 345 "Accept timed out"); 346 } else if (rv == -1) { 347 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 348 } else if (rv == -2) { 349 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 350 "operation interrupted"); 351 } 352 } 353 354 /* 355 * Class: java_net_TwoStacksPlainSocketImpl 356 * Method: available0 357 * Signature: (I)I 358 */ 359 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_available0 360 (JNIEnv *env, jclass clazz, jint fd) { 361 jint available = -1; 362 363 if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) { 364 NET_ThrowNew(env, WSAGetLastError(), "socket available"); 365 } 366 367 return available; 368 } 369 370 /* 371 * Class: java_net_TwoStacksPlainSocketImpl 372 * Method: close0 373 * Signature: (I)V 374 */ 375 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_close0 376 (JNIEnv *env, jclass clazz, jint fd) { 377 NET_SocketClose(fd); 378 } 379 380 /* 381 * Class: java_net_TwoStacksPlainSocketImpl 382 * Method: shutdown0 383 * Signature: (II)V 384 */ 385 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_shutdown0 386 (JNIEnv *env, jclass clazz, jint fd, jint howto) { 387 shutdown(fd, howto); 388 } 389 390 391 /* 392 * Class: java_net_TwoStacksPlainSocketImpl 393 * Method: setIntOption 394 * Signature: (III)V 395 */ 396 JNIEXPORT void JNICALL 397 Java_java_net_TwoStacksPlainSocketImpl_setIntOption 398 (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) 399 { 400 int level = 0, opt = 0; 401 struct linger linger = {0, 0}; 402 char *parg; 403 int arglen; 404 405 if (NET_MapSocketOption(cmd, &level, &opt) < 0) { 406 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 407 return; 408 } 409 410 if (opt == java_net_SocketOptions_SO_LINGER) { 411 parg = (char *)&linger; 412 arglen = sizeof(linger); 413 if (value >= 0) { 414 linger.l_onoff = 1; 415 linger.l_linger = (unsigned short)value; 416 } else { 417 linger.l_onoff = 0; 418 linger.l_linger = 0; 419 } 420 } else { 421 parg = (char *)&value; 422 arglen = sizeof(value); 423 } 424 425 if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) { 426 NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); 427 } 428 } 429 430 /* 431 * Class: java_net_TwoStacksPlainSocketImpl 432 * Method: setSoTimeout0 433 * Signature: (II)V 434 */ 435 JNIEXPORT void JNICALL 436 Java_java_net_TwoStacksPlainSocketImpl_setSoTimeout0 437 (JNIEnv *env, jclass clazz, jint fd, jint timeout) 438 { 439 /* 440 * SO_TIMEOUT is the socket option used to specify the timeout 441 * for ServerSocket.accept and Socket.getInputStream().read. 442 * It does not typically map to a native level socket option. 443 * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO 444 * socket option to specify a receive timeout on the socket. This 445 * receive timeout is applicable to Socket only and the socket 446 * option should not be set on ServerSocket. 447 */ 448 449 /* 450 * SO_RCVTIMEO is only supported on Microsoft's implementation 451 * of Windows Sockets so if WSAENOPROTOOPT returned then 452 * reset flag and timeout will be implemented using 453 * select() -- see SocketInputStream.socketRead. 454 */ 455 if (isRcvTimeoutSupported) { 456 /* 457 * Disable SO_RCVTIMEO if timeout is <= 5 second. 458 */ 459 if (timeout <= 5000) { 460 timeout = 0; 461 } 462 463 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 464 sizeof(timeout)) < 0) { 465 int err = WSAGetLastError(); 466 if (err == WSAENOPROTOOPT) { 467 isRcvTimeoutSupported = JNI_FALSE; 468 } else { 469 NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO"); 470 } 471 } 472 } 473 } 474 475 /* 476 * Class: java_net_TwoStacksPlainSocketImpl 477 * Method: getIntOption 478 * Signature: (II)I 479 */ 480 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_getIntOption 481 (JNIEnv *env, jclass clazz, jint fd, jint cmd) 482 { 483 int level = 0, opt = 0; 484 int result=0; 485 struct linger linger = {0, 0}; 486 char *arg; 487 int arglen; 488 489 if (NET_MapSocketOption(cmd, &level, &opt) < 0) { 490 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 491 return -1; 492 } 493 494 if (opt == java_net_SocketOptions_SO_LINGER) { 495 arg = (char *)&linger; 496 arglen = sizeof(linger); 497 } else { 498 arg = (char *)&result; 499 arglen = sizeof(result); 500 } 501 502 if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) { 503 NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); 504 return -1; 505 } 506 507 if (opt == java_net_SocketOptions_SO_LINGER) 508 return linger.l_onoff ? linger.l_linger : -1; 509 else 510 return result; 511 } 512 513 514 /* 515 * Class: java_net_TwoStacksPlainSocketImpl 516 * Method: sendOOB 517 * Signature: (II)V 518 */ 519 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_sendOOB 520 (JNIEnv *env, jclass clazz, jint fd, jint data) { 521 jint n; 522 unsigned char d = (unsigned char) data & 0xff; 523 524 n = send(fd, (char *)&data, 1, MSG_OOB); 525 if (n == SOCKET_ERROR) { 526 NET_ThrowNew(env, WSAGetLastError(), "send"); 527 } 528 } 529 530 /* 531 * Class: java_net_TwoStacksPlainSocketImpl 532 * Method: configureBlocking 533 * Signature: (IZ)V 534 */ 535 JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_configureBlocking 536 (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) { 537 u_long arg; 538 int result; 539 540 if (blocking == JNI_TRUE) { 541 arg = SET_BLOCKING; // 0 542 } else { 543 arg = SET_NONBLOCKING; // 1 544 } 545 546 result = ioctlsocket(fd, FIONBIO, &arg); 547 if (result == SOCKET_ERROR) { 548 NET_ThrowNew(env, WSAGetLastError(), "configureBlocking"); 549 } 550 }