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