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