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