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