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