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