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_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 = 1; // ENABLE 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 int count = 0; 744 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 745 jint fd; 746 747 if (IS_NULL(fdObj)) { 748 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 749 "Socket closed"); 750 return -1; 751 } else { 752 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 753 } 754 if (NET_SocketAvailable(fd, &count) != 0) { 755 if (errno == ECONNRESET) { 756 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 757 } else { 758 JNU_ThrowByNameWithMessageAndLastError 759 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 760 } 761 } 762 return (jint) count; 763 } 764 765 /* 766 * Class: java_net_PlainSocketImpl 767 * Method: socketClose0 768 * Signature: (Z)V 769 */ 770 JNIEXPORT void JNICALL 771 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 772 jboolean useDeferredClose) { 773 774 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 775 jint fd; 776 777 if (IS_NULL(fdObj)) { 778 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 779 "socket already closed"); 780 return; 781 } else { 782 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 783 } 784 if (fd != -1) { 785 if (useDeferredClose && marker_fd >= 0) { 786 NET_Dup2(marker_fd, fd); 787 } else { 788 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 789 NET_SocketClose(fd); 790 } 791 } 792 } 793 794 /* 795 * Class: java_net_PlainSocketImpl 796 * Method: socketShutdown 797 * Signature: (I)V 798 */ 799 JNIEXPORT void JNICALL 800 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 801 jint howto) 802 { 803 804 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 805 jint fd; 806 807 /* 808 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 809 * -1 already? 810 */ 811 if (IS_NULL(fdObj)) { 812 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 813 "socket already closed"); 814 return; 815 } else { 816 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 817 } 818 shutdown(fd, howto); 819 } 820 821 822 /* 823 * Class: java_net_PlainSocketImpl 824 * Method: socketSetOption0 825 * Signature: (IZLjava/lang/Object;)V 826 */ 827 JNIEXPORT void JNICALL 828 Java_java_net_PlainSocketImpl_socketSetOption0 829 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value) 830 { 831 int fd; 832 int level, optname, optlen; 833 union { 834 int i; 835 struct linger ling; 836 } optval; 837 838 /* 839 * Check that socket hasn't been closed 840 */ 841 fd = getFD(env, this); 842 if (fd < 0) { 843 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 844 "Socket closed"); 845 return; 846 } 847 848 /* 849 * SO_TIMEOUT is a NOOP on Solaris/Linux 850 */ 851 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 852 return; 853 } 854 855 /* 856 * Map the Java level socket option to the platform specific 857 * level and option name. 858 */ 859 if (NET_MapSocketOption(cmd, &level, &optname)) { 860 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 861 return; 862 } 863 864 switch (cmd) { 865 case java_net_SocketOptions_SO_SNDBUF : 866 case java_net_SocketOptions_SO_RCVBUF : 867 case java_net_SocketOptions_SO_LINGER : 868 case java_net_SocketOptions_IP_TOS : 869 { 870 jclass cls; 871 jfieldID fid; 872 873 cls = (*env)->FindClass(env, "java/lang/Integer"); 874 CHECK_NULL(cls); 875 fid = (*env)->GetFieldID(env, cls, "value", "I"); 876 CHECK_NULL(fid); 877 878 if (cmd == java_net_SocketOptions_SO_LINGER) { 879 if (on) { 880 optval.ling.l_onoff = 1; 881 optval.ling.l_linger = (*env)->GetIntField(env, value, fid); 882 } else { 883 optval.ling.l_onoff = 0; 884 optval.ling.l_linger = 0; 885 } 886 optlen = sizeof(optval.ling); 887 } else { 888 optval.i = (*env)->GetIntField(env, value, fid); 889 optlen = sizeof(optval.i); 890 } 891 892 break; 893 } 894 895 /* Boolean -> int */ 896 default : 897 optval.i = (on ? 1 : 0); 898 optlen = sizeof(optval.i); 899 900 } 901 902 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 903 #if defined(__solaris__) || defined(_AIX) 904 if (errno == EINVAL) { 905 // On Solaris setsockopt will set errno to EINVAL if the socket 906 // is closed. The default error message is then confusing 907 char fullMsg[128]; 908 jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer"); 909 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); 910 return; 911 } 912 #endif /* __solaris__ */ 913 JNU_ThrowByNameWithMessageAndLastError 914 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 915 } 916 } 917 918 /* 919 * Class: java_net_PlainSocketImpl 920 * Method: socketGetOption 921 * Signature: (ILjava/lang/Object;)I 922 */ 923 JNIEXPORT jint JNICALL 924 Java_java_net_PlainSocketImpl_socketGetOption 925 (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj) 926 { 927 int fd; 928 int level, optname, optlen; 929 union { 930 int i; 931 struct linger ling; 932 } optval; 933 934 /* 935 * Check that socket hasn't been closed 936 */ 937 fd = getFD(env, this); 938 if (fd < 0) { 939 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 940 "Socket closed"); 941 return -1; 942 } 943 944 /* 945 * SO_BINDADDR isn't a socket option 946 */ 947 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 948 SOCKETADDRESS sa; 949 socklen_t len = sizeof(SOCKETADDRESS); 950 int port; 951 jobject iaObj; 952 jclass iaCntrClass; 953 jfieldID iaFieldID; 954 955 if (getsockname(fd, &sa.sa, &len) < 0) { 956 JNU_ThrowByNameWithMessageAndLastError 957 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 958 return -1; 959 } 960 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 961 CHECK_NULL_RETURN(iaObj, -1); 962 963 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 964 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 965 CHECK_NULL_RETURN(iaFieldID, -1); 966 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 967 return 0; /* notice change from before */ 968 } 969 970 /* 971 * Map the Java level socket option to the platform specific 972 * level and option name. 973 */ 974 if (NET_MapSocketOption(cmd, &level, &optname)) { 975 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 976 return -1; 977 } 978 979 /* 980 * Args are int except for SO_LINGER 981 */ 982 if (cmd == java_net_SocketOptions_SO_LINGER) { 983 optlen = sizeof(optval.ling); 984 } else { 985 optlen = sizeof(optval.i); 986 } 987 988 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 989 JNU_ThrowByNameWithMessageAndLastError 990 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 991 return -1; 992 } 993 994 switch (cmd) { 995 case java_net_SocketOptions_SO_LINGER: 996 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 997 998 case java_net_SocketOptions_SO_SNDBUF: 999 case java_net_SocketOptions_SO_RCVBUF: 1000 case java_net_SocketOptions_IP_TOS: 1001 return optval.i; 1002 1003 default : 1004 return (optval.i == 0) ? -1 : 1; 1005 } 1006 } 1007 1008 1009 /* 1010 * Class: java_net_PlainSocketImpl 1011 * Method: socketSendUrgentData 1012 * Signature: (B)V 1013 */ 1014 JNIEXPORT void JNICALL 1015 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 1016 jint data) { 1017 /* The fd field */ 1018 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1019 int n, fd; 1020 unsigned char d = data & 0xFF; 1021 1022 if (IS_NULL(fdObj)) { 1023 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1024 return; 1025 } else { 1026 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1027 /* Bug 4086704 - If the Socket associated with this file descriptor 1028 * was closed (sysCloseFD), the file descriptor is set to -1. 1029 */ 1030 if (fd == -1) { 1031 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1032 return; 1033 } 1034 1035 } 1036 n = NET_Send(fd, (char *)&d, 1, MSG_OOB); 1037 if (n == -1) { 1038 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 1039 } 1040 }