1 /* 2 * Copyright (c) 1997, 2020, 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 <errno.h> 26 27 #include "jvm.h" 28 #include "net_util.h" 29 30 #include "java_net_SocketOptions.h" 31 #include "java_net_PlainSocketImpl.h" 32 33 /************************************************************************ 34 * PlainSocketImpl 35 */ 36 37 static jfieldID IO_fd_fdID; 38 39 jfieldID psi_fdID; 40 jfieldID psi_addressID; 41 jfieldID psi_ipaddressID; 42 jfieldID psi_portID; 43 jfieldID psi_localportID; 44 jfieldID psi_timeoutID; 45 jfieldID psi_trafficClassID; 46 jfieldID psi_fdLockID; 47 jfieldID psi_closePendingID; 48 49 /* 50 * file descriptor used for dup2 51 */ 52 static int marker_fd = -1; 53 54 55 #define SET_NONBLOCKING(fd) { \ 56 int flags = fcntl(fd, F_GETFL); \ 57 flags |= O_NONBLOCK; \ 58 fcntl(fd, F_SETFL, flags); \ 59 } 60 61 #define SET_BLOCKING(fd) { \ 62 int flags = fcntl(fd, F_GETFL); \ 63 flags &= ~O_NONBLOCK; \ 64 fcntl(fd, F_SETFL, flags); \ 65 } 66 67 /* 68 * Create the marker file descriptor by establishing a loopback connection 69 * which we shutdown but do not close the fd. The result is an fd that 70 * can be used for read/write. 71 */ 72 static int getMarkerFD() 73 { 74 int sv[2]; 75 76 #ifdef AF_UNIX 77 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { 78 return -1; 79 } 80 #else 81 return -1; 82 #endif 83 84 /* 85 * Finally shutdown sv[0] (any reads to this fd will get 86 * EOF; any writes will get an error). 87 */ 88 shutdown(sv[0], 2); 89 close(sv[1]); 90 91 return sv[0]; 92 } 93 94 /* 95 * Return the file descriptor given a PlainSocketImpl 96 */ 97 static int getFD(JNIEnv *env, jobject this) { 98 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 99 CHECK_NULL_RETURN(fdObj, -1); 100 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 101 } 102 103 /* 104 * The initroto function is called whenever PlainSocketImpl is 105 * loaded, to cache field IDs for efficiency. This is called every time 106 * the Java class is loaded. 107 * 108 * Class: java_net_PlainSocketImpl 109 * Method: initProto 110 * Signature: ()V 111 */ 112 JNIEXPORT void JNICALL 113 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) { 114 psi_fdID = (*env)->GetFieldID(env, cls , "fd", 115 "Ljava/io/FileDescriptor;"); 116 CHECK_NULL(psi_fdID); 117 psi_addressID = (*env)->GetFieldID(env, cls, "address", 118 "Ljava/net/InetAddress;"); 119 CHECK_NULL(psi_addressID); 120 psi_portID = (*env)->GetFieldID(env, cls, "port", "I"); 121 CHECK_NULL(psi_portID); 122 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I"); 123 CHECK_NULL(psi_localportID); 124 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); 125 CHECK_NULL(psi_timeoutID); 126 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); 127 CHECK_NULL(psi_trafficClassID); 128 psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock", 129 "Ljava/lang/Object;"); 130 CHECK_NULL(psi_fdLockID); 131 psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z"); 132 CHECK_NULL(psi_closePendingID); 133 IO_fd_fdID = NET_GetFileDescriptorID(env); 134 CHECK_NULL(IO_fd_fdID); 135 136 initInetAddressIDs(env); 137 JNU_CHECK_EXCEPTION(env); 138 139 /* Create the marker fd used for dup2 */ 140 marker_fd = getMarkerFD(); 141 } 142 143 /* a global reference to the java.net.SocketException class. In 144 * socketCreate, we ensure that this is initialized. This is to 145 * prevent the problem where socketCreate runs out of file 146 * descriptors, and is then unable to load the exception class. 147 */ 148 static jclass socketExceptionCls; 149 150 /* 151 * Class: java_net_PlainSocketImpl 152 * Method: socketCreate 153 * Signature: (ZZ)V */ 154 JNIEXPORT void JNICALL 155 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, 156 jboolean stream, jboolean isServer) { 157 jobject fdObj, ssObj; 158 int fd; 159 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 160 int domain = ipv6_available() ? AF_INET6 : AF_INET; 161 162 if (socketExceptionCls == NULL) { 163 jclass c = (*env)->FindClass(env, "java/net/SocketException"); 164 CHECK_NULL(c); 165 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c); 166 CHECK_NULL(socketExceptionCls); 167 } 168 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 169 170 if (fdObj == NULL) { 171 (*env)->ThrowNew(env, socketExceptionCls, "null fd object"); 172 return; 173 } 174 175 if ((fd = socket(domain, type, 0)) == -1) { 176 /* note: if you run out of fds, you may not be able to load 177 * the exception class, and get a NoClassDefFoundError 178 * instead. 179 */ 180 NET_ThrowNew(env, errno, "can't create socket"); 181 return; 182 } 183 184 /* 185 * If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support. 186 */ 187 if (domain == AF_INET6 && ipv4_available()) { 188 int arg = 0; 189 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 190 sizeof(int)) < 0) { 191 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); 192 close(fd); 193 return; 194 } 195 } 196 197 /* 198 * If this is a server socket then enable SO_REUSEADDR 199 * automatically and set to non blocking. 200 */ 201 if (isServer) { 202 int arg = 1; 203 SET_NONBLOCKING(fd); 204 if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 205 sizeof(arg)) < 0) { 206 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR"); 207 close(fd); 208 return; 209 } 210 } 211 212 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 213 } 214 215 /* 216 * inetAddress is the address object passed to the socket connect 217 * call. 218 * 219 * Class: java_net_PlainSocketImpl 220 * Method: socketConnect 221 * Signature: (Ljava/net/InetAddress;I)V 222 */ 223 JNIEXPORT void JNICALL 224 Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this, 225 jobject iaObj, jint port, 226 jint timeout) 227 { 228 jint localport = (*env)->GetIntField(env, this, psi_localportID); 229 int len = 0; 230 /* fdObj is the FileDescriptor field on this */ 231 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 232 233 jclass clazz = (*env)->GetObjectClass(env, this); 234 235 jobject fdLock; 236 237 jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID); 238 239 /* fd is an int field on iaObj */ 240 jint fd; 241 242 SOCKETADDRESS sa; 243 /* The result of the connection */ 244 int connect_rv = -1; 245 246 if (IS_NULL(fdObj)) { 247 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 248 return; 249 } else { 250 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 251 } 252 if (IS_NULL(iaObj)) { 253 JNU_ThrowNullPointerException(env, "inet address argument null."); 254 return; 255 } 256 257 /* connect */ 258 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len, 259 JNI_TRUE) != 0) { 260 return; 261 } 262 263 if (trafficClass != 0 && ipv6_available()) { 264 NET_SetTrafficClass(&sa, trafficClass); 265 } 266 267 if (timeout <= 0) { 268 connect_rv = NET_Connect(fd, &sa.sa, len); 269 } else { 270 /* 271 * A timeout was specified. We put the socket into non-blocking 272 * mode, connect, and then wait for the connection to be 273 * established, fail, or timeout. 274 */ 275 SET_NONBLOCKING(fd); 276 277 /* no need to use NET_Connect as non-blocking */ 278 connect_rv = connect(fd, &sa.sa, len); 279 280 /* connection not established immediately */ 281 if (connect_rv != 0) { 282 socklen_t optlen; 283 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 284 jlong prevNanoTime = JVM_NanoTime(env, 0); 285 286 if (errno != EINPROGRESS) { 287 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 288 "connect failed"); 289 SET_BLOCKING(fd); 290 return; 291 } 292 293 /* 294 * Wait for the connection to be established or a 295 * timeout occurs. poll needs to handle EINTR in 296 * case lwp sig handler redirects any process signals to 297 * this thread. 298 */ 299 while (1) { 300 jlong newNanoTime; 301 struct pollfd pfd; 302 pfd.fd = fd; 303 pfd.events = POLLOUT; 304 305 errno = 0; 306 connect_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); 307 308 if (connect_rv >= 0) { 309 break; 310 } 311 if (errno != EINTR) { 312 break; 313 } 314 315 /* 316 * The poll was interrupted so adjust timeout and 317 * restart 318 */ 319 newNanoTime = JVM_NanoTime(env, 0); 320 nanoTimeout -= (newNanoTime - prevNanoTime); 321 if (nanoTimeout < NET_NSEC_PER_MSEC) { 322 connect_rv = 0; 323 break; 324 } 325 prevNanoTime = newNanoTime; 326 327 } /* while */ 328 329 if (connect_rv == 0) { 330 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 331 "connect timed out"); 332 333 /* 334 * Timeout out but connection may still be established. 335 * At the high level it should be closed immediately but 336 * just in case we make the socket blocking again and 337 * shutdown input & output. 338 */ 339 SET_BLOCKING(fd); 340 shutdown(fd, 2); 341 return; 342 } 343 344 /* has connection been established */ 345 optlen = sizeof(connect_rv); 346 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 347 &optlen) <0) { 348 connect_rv = errno; 349 } 350 } 351 352 /* make socket blocking again */ 353 SET_BLOCKING(fd); 354 355 /* restore errno */ 356 if (connect_rv != 0) { 357 errno = connect_rv; 358 connect_rv = -1; 359 } 360 } 361 362 /* report the appropriate exception */ 363 if (connect_rv < 0) { 364 365 #ifdef __linux__ 366 /* 367 * Linux/GNU distribution setup /etc/hosts so that 368 * InetAddress.getLocalHost gets back the loopback address 369 * rather than the host address. Thus a socket can be 370 * bound to the loopback address and the connect will 371 * fail with EADDRNOTAVAIL. In addition the Linux kernel 372 * returns the wrong error in this case - it returns EINVAL 373 * instead of EADDRNOTAVAIL. We handle this here so that 374 * a more descriptive exception text is used. 375 */ 376 if (connect_rv == -1 && errno == EINVAL) { 377 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 378 "Invalid argument or cannot assign requested address"); 379 return; 380 } 381 #endif 382 #if defined(EPROTO) 383 if (errno == EPROTO) { 384 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException", 385 "Protocol error"); 386 return; 387 } 388 #endif 389 if (errno == ECONNREFUSED) { 390 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 391 "Connection refused"); 392 } else if (errno == ETIMEDOUT) { 393 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 394 "Connection timed out"); 395 } else if (errno == EHOSTUNREACH) { 396 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException", 397 "Host unreachable"); 398 } else if (errno == EADDRNOTAVAIL) { 399 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException", 400 "Address not available"); 401 } else if ((errno == EISCONN) || (errno == EBADF)) { 402 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 403 "Socket closed"); 404 } else { 405 JNU_ThrowByNameWithMessageAndLastError 406 (env, JNU_JAVANETPKG "SocketException", "connect failed"); 407 } 408 return; 409 } 410 411 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 412 413 /* set the remote peer address and port */ 414 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 415 (*env)->SetIntField(env, this, psi_portID, port); 416 417 /* 418 * we need to initialize the local port field if bind was called 419 * previously to the connect (by the client) then localport field 420 * will already be initialized 421 */ 422 if (localport == 0) { 423 /* Now that we're a connected socket, let's extract the port number 424 * that the system chose for us and store it in the Socket object. 425 */ 426 socklen_t slen = sizeof(SOCKETADDRESS); 427 if (getsockname(fd, &sa.sa, &slen) == -1) { 428 JNU_ThrowByNameWithMessageAndLastError 429 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 430 } else { 431 localport = NET_GetPortFromSockaddr(&sa); 432 (*env)->SetIntField(env, this, psi_localportID, localport); 433 } 434 } 435 } 436 437 /* 438 * Class: java_net_PlainSocketImpl 439 * Method: socketBind 440 * Signature: (Ljava/net/InetAddress;I)V 441 */ 442 JNIEXPORT void JNICALL 443 Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this, 444 jobject iaObj, jint localport) { 445 446 /* fdObj is the FileDescriptor field on this */ 447 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 448 /* fd is an int field on fdObj */ 449 int fd; 450 int len = 0; 451 SOCKETADDRESS sa; 452 453 if (IS_NULL(fdObj)) { 454 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 455 "Socket closed"); 456 return; 457 } else { 458 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 459 } 460 if (IS_NULL(iaObj)) { 461 JNU_ThrowNullPointerException(env, "iaObj is null."); 462 return; 463 } 464 465 /* bind */ 466 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, 467 &len, JNI_TRUE) != 0) { 468 return; 469 } 470 471 if (NET_Bind(fd, &sa, len) < 0) { 472 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 473 errno == EPERM || errno == EACCES) { 474 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException", 475 "Bind failed"); 476 } else { 477 JNU_ThrowByNameWithMessageAndLastError 478 (env, JNU_JAVANETPKG "SocketException", "Bind failed"); 479 } 480 return; 481 } 482 483 /* set the address */ 484 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 485 486 /* initialize the local port */ 487 if (localport == 0) { 488 socklen_t slen = sizeof(SOCKETADDRESS); 489 /* Now that we're a connected socket, let's extract the port number 490 * that the system chose for us and store it in the Socket object. 491 */ 492 if (getsockname(fd, &sa.sa, &slen) == -1) { 493 JNU_ThrowByNameWithMessageAndLastError 494 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 495 return; 496 } 497 localport = NET_GetPortFromSockaddr(&sa); 498 (*env)->SetIntField(env, this, psi_localportID, localport); 499 } else { 500 (*env)->SetIntField(env, this, psi_localportID, localport); 501 } 502 } 503 504 /* 505 * Class: java_net_PlainSocketImpl 506 * Method: socketListen 507 * Signature: (I)V 508 */ 509 JNIEXPORT void JNICALL 510 Java_java_net_PlainSocketImpl_socketListen(JNIEnv *env, jobject this, 511 jint count) 512 { 513 /* this FileDescriptor fd field */ 514 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 515 /* fdObj's int fd field */ 516 int fd; 517 518 if (IS_NULL(fdObj)) { 519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 520 "Socket closed"); 521 return; 522 } else { 523 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 524 } 525 526 /* 527 * Workaround for bugid 4101691 in Solaris 2.6. See 4106600. 528 * If listen backlog is Integer.MAX_VALUE then subtract 1. 529 */ 530 if (count == 0x7fffffff) 531 count -= 1; 532 533 if (listen(fd, count) == -1) { 534 JNU_ThrowByNameWithMessageAndLastError 535 (env, JNU_JAVANETPKG "SocketException", "Listen failed"); 536 } 537 } 538 539 /* 540 * Class: java_net_PlainSocketImpl 541 * Method: socketAccept 542 * Signature: (Ljava/net/SocketImpl;)V 543 */ 544 JNIEXPORT void JNICALL 545 Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 546 jobject socket) 547 { 548 /* fields on this */ 549 int port; 550 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID); 551 jlong prevNanoTime = 0; 552 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 553 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 554 555 /* the FileDescriptor field on socket */ 556 jobject socketFdObj; 557 /* the InetAddress field on socket */ 558 jobject socketAddressObj; 559 560 /* the ServerSocket fd int field on fdObj */ 561 jint fd; 562 563 /* accepted fd */ 564 jint newfd; 565 566 SOCKETADDRESS sa; 567 socklen_t slen = sizeof(SOCKETADDRESS); 568 569 if (IS_NULL(fdObj)) { 570 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 571 "Socket closed"); 572 return; 573 } else { 574 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 575 } 576 if (IS_NULL(socket)) { 577 JNU_ThrowNullPointerException(env, "socket is null"); 578 return; 579 } 580 581 /* 582 * accept connection but ignore ECONNABORTED indicating that 583 * connection was eagerly accepted by the OS but was reset 584 * before accept() was called. 585 * 586 * If accept timeout in place and timeout is adjusted with 587 * each ECONNABORTED or EWOULDBLOCK or EAGAIN to ensure that 588 * semantics of timeout are preserved. 589 */ 590 for (;;) { 591 int ret; 592 jlong currNanoTime; 593 594 /* first usage pick up current time */ 595 if (prevNanoTime == 0 && nanoTimeout > 0) { 596 prevNanoTime = JVM_NanoTime(env, 0); 597 } 598 599 /* passing a timeout of 0 to poll will return immediately, 600 but in the case of ServerSocket 0 means infinite. */ 601 if (timeout <= 0) { 602 ret = NET_Timeout(env, fd, -1, 0); 603 } else { 604 ret = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime); 605 } 606 if (ret == 0) { 607 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 608 "Accept timed out"); 609 return; 610 } else if (ret == -1) { 611 if (errno == EBADF) { 612 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 613 } else if (errno == ENOMEM) { 614 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 615 } else { 616 JNU_ThrowByNameWithMessageAndLastError 617 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 618 } 619 return; 620 } 621 622 newfd = NET_Accept(fd, &sa.sa, &slen); 623 624 /* connection accepted */ 625 if (newfd >= 0) { 626 SET_BLOCKING(newfd); 627 break; 628 } 629 630 /* non (ECONNABORTED or EWOULDBLOCK or EAGAIN) error */ 631 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK || errno == EAGAIN)) { 632 break; 633 } 634 635 /* ECONNABORTED or EWOULDBLOCK or EAGAIN error so adjust timeout if there is one. */ 636 if (nanoTimeout >= NET_NSEC_PER_MSEC) { 637 currNanoTime = JVM_NanoTime(env, 0); 638 nanoTimeout -= (currNanoTime - prevNanoTime); 639 if (nanoTimeout < NET_NSEC_PER_MSEC) { 640 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 641 "Accept timed out"); 642 return; 643 } 644 prevNanoTime = currNanoTime; 645 } 646 } 647 648 if (newfd < 0) { 649 if (newfd == -2) { 650 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 651 "operation interrupted"); 652 } else { 653 if (errno == EINVAL) { 654 errno = EBADF; 655 } 656 if (errno == EBADF) { 657 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 658 } else { 659 JNU_ThrowByNameWithMessageAndLastError 660 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 661 } 662 } 663 return; 664 } 665 666 /* 667 * fill up the remote peer port and address in the new socket structure. 668 */ 669 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 670 if (socketAddressObj == NULL) { 671 /* should be pending exception */ 672 close(newfd); 673 return; 674 } 675 676 /* 677 * Populate SocketImpl.fd.fd 678 */ 679 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 680 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 681 682 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 683 (*env)->SetIntField(env, socket, psi_portID, port); 684 /* also fill up the local port information */ 685 port = (*env)->GetIntField(env, this, psi_localportID); 686 (*env)->SetIntField(env, socket, psi_localportID, port); 687 } 688 689 690 /* 691 * Class: java_net_PlainSocketImpl 692 * Method: socketAvailable 693 * Signature: ()I 694 */ 695 JNIEXPORT jint JNICALL 696 Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) { 697 int count = 0; 698 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 699 jint fd; 700 701 if (IS_NULL(fdObj)) { 702 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 703 "Socket closed"); 704 return -1; 705 } else { 706 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 707 } 708 if (NET_SocketAvailable(fd, &count) != 0) { 709 if (errno == ECONNRESET) { 710 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 711 } else { 712 JNU_ThrowByNameWithMessageAndLastError 713 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 714 } 715 } 716 return (jint) count; 717 } 718 719 /* 720 * Class: java_net_PlainSocketImpl 721 * Method: socketClose0 722 * Signature: (Z)V 723 */ 724 JNIEXPORT void JNICALL 725 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 726 jboolean useDeferredClose) { 727 728 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 729 jint fd; 730 731 if (IS_NULL(fdObj)) { 732 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 733 "socket already closed"); 734 return; 735 } else { 736 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 737 } 738 if (fd != -1) { 739 if (useDeferredClose && marker_fd >= 0) { 740 NET_Dup2(marker_fd, fd); 741 } else { 742 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 743 NET_SocketClose(fd); 744 } 745 } 746 } 747 748 /* 749 * Class: java_net_PlainSocketImpl 750 * Method: socketShutdown 751 * Signature: (I)V 752 */ 753 JNIEXPORT void JNICALL 754 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 755 jint howto) 756 { 757 758 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 759 jint fd; 760 761 /* 762 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 763 * -1 already? 764 */ 765 if (IS_NULL(fdObj)) { 766 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 767 "socket already closed"); 768 return; 769 } else { 770 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 771 } 772 shutdown(fd, howto); 773 } 774 775 776 /* 777 * Class: java_net_PlainSocketImpl 778 * Method: socketSetOption0 779 * Signature: (IZLjava/lang/Object;)V 780 */ 781 JNIEXPORT void JNICALL 782 Java_java_net_PlainSocketImpl_socketSetOption0 783 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value) 784 { 785 int fd; 786 int level, optname, optlen; 787 union { 788 int i; 789 struct linger ling; 790 } optval; 791 792 /* 793 * Check that socket hasn't been closed 794 */ 795 fd = getFD(env, this); 796 if (fd < 0) { 797 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 798 "Socket closed"); 799 return; 800 } 801 802 /* 803 * SO_TIMEOUT is a NOOP on Solaris/Linux 804 */ 805 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 806 return; 807 } 808 809 /* 810 * Map the Java level socket option to the platform specific 811 * level and option name. 812 */ 813 if (NET_MapSocketOption(cmd, &level, &optname)) { 814 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 815 return; 816 } 817 818 switch (cmd) { 819 case java_net_SocketOptions_SO_SNDBUF : 820 case java_net_SocketOptions_SO_RCVBUF : 821 case java_net_SocketOptions_SO_LINGER : 822 case java_net_SocketOptions_IP_TOS : 823 { 824 jclass cls; 825 jfieldID fid; 826 827 cls = (*env)->FindClass(env, "java/lang/Integer"); 828 CHECK_NULL(cls); 829 fid = (*env)->GetFieldID(env, cls, "value", "I"); 830 CHECK_NULL(fid); 831 832 if (cmd == java_net_SocketOptions_SO_LINGER) { 833 if (on) { 834 optval.ling.l_onoff = 1; 835 optval.ling.l_linger = (*env)->GetIntField(env, value, fid); 836 } else { 837 optval.ling.l_onoff = 0; 838 optval.ling.l_linger = 0; 839 } 840 optlen = sizeof(optval.ling); 841 } else { 842 optval.i = (*env)->GetIntField(env, value, fid); 843 optlen = sizeof(optval.i); 844 } 845 846 break; 847 } 848 849 /* Boolean -> int */ 850 default : 851 optval.i = (on ? 1 : 0); 852 optlen = sizeof(optval.i); 853 854 } 855 856 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 857 #if defined(_AIX) 858 if (errno == EINVAL) { 859 // On AIX setsockopt will set errno to EINVAL if the socket 860 // is closed. The default error message is then confusing 861 char fullMsg[128]; 862 jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer"); 863 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); 864 return; 865 } 866 #endif /* _AIX */ 867 JNU_ThrowByNameWithMessageAndLastError 868 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 869 } 870 } 871 872 /* 873 * Class: java_net_PlainSocketImpl 874 * Method: socketGetOption 875 * Signature: (ILjava/lang/Object;)I 876 */ 877 JNIEXPORT jint JNICALL 878 Java_java_net_PlainSocketImpl_socketGetOption 879 (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj) 880 { 881 int fd; 882 int level, optname, optlen; 883 union { 884 int i; 885 struct linger ling; 886 } optval; 887 888 /* 889 * Check that socket hasn't been closed 890 */ 891 fd = getFD(env, this); 892 if (fd < 0) { 893 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 894 "Socket closed"); 895 return -1; 896 } 897 898 /* 899 * SO_BINDADDR isn't a socket option 900 */ 901 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 902 SOCKETADDRESS sa; 903 socklen_t len = sizeof(SOCKETADDRESS); 904 int port; 905 jobject iaObj; 906 jclass iaCntrClass; 907 jfieldID iaFieldID; 908 909 if (getsockname(fd, &sa.sa, &len) < 0) { 910 JNU_ThrowByNameWithMessageAndLastError 911 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 912 return -1; 913 } 914 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 915 CHECK_NULL_RETURN(iaObj, -1); 916 917 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 918 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 919 CHECK_NULL_RETURN(iaFieldID, -1); 920 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 921 return 0; /* notice change from before */ 922 } 923 924 /* 925 * Map the Java level socket option to the platform specific 926 * level and option name. 927 */ 928 if (NET_MapSocketOption(cmd, &level, &optname)) { 929 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 930 return -1; 931 } 932 933 /* 934 * Args are int except for SO_LINGER 935 */ 936 if (cmd == java_net_SocketOptions_SO_LINGER) { 937 optlen = sizeof(optval.ling); 938 } else { 939 optlen = sizeof(optval.i); 940 } 941 942 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 943 JNU_ThrowByNameWithMessageAndLastError 944 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 945 return -1; 946 } 947 948 switch (cmd) { 949 case java_net_SocketOptions_SO_LINGER: 950 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 951 952 case java_net_SocketOptions_SO_SNDBUF: 953 case java_net_SocketOptions_SO_RCVBUF: 954 case java_net_SocketOptions_IP_TOS: 955 return optval.i; 956 957 default : 958 return (optval.i == 0) ? -1 : 1; 959 } 960 } 961 962 963 /* 964 * Class: java_net_PlainSocketImpl 965 * Method: socketSendUrgentData 966 * Signature: (B)V 967 */ 968 JNIEXPORT void JNICALL 969 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 970 jint data) { 971 /* The fd field */ 972 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 973 int n, fd; 974 unsigned char d = data & 0xFF; 975 976 if (IS_NULL(fdObj)) { 977 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 978 return; 979 } else { 980 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 981 /* Bug 4086704 - If the Socket associated with this file descriptor 982 * was closed (sysCloseFD), the file descriptor is set to -1. 983 */ 984 if (fd == -1) { 985 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 986 return; 987 } 988 989 } 990 n = NET_Send(fd, (char *)&d, 1, MSG_OOB); 991 if (n == -1) { 992 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 993 } 994 }