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