1 /* 2 * Copyright (c) 1997, 2016, 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 JNU_ThrowByNameWithMessageAndLastError 480 (env, JNU_JAVANETPKG "SocketException", "connect failed"); 481 } 482 return; 483 } 484 485 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 486 487 /* set the remote peer address and port */ 488 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 489 (*env)->SetIntField(env, this, psi_portID, port); 490 491 /* 492 * we need to initialize the local port field if bind was called 493 * previously to the connect (by the client) then localport field 494 * will already be initialized 495 */ 496 if (localport == 0) { 497 /* Now that we're a connected socket, let's extract the port number 498 * that the system chose for us and store it in the Socket object. 499 */ 500 socklen_t slen = SOCKADDR_LEN; 501 if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) { 502 JNU_ThrowByNameWithMessageAndLastError 503 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 504 } else { 505 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him); 506 (*env)->SetIntField(env, this, psi_localportID, localport); 507 } 508 } 509 } 510 511 /* 512 * Class: java_net_PlainSocketImpl 513 * Method: socketBind 514 * Signature: (Ljava/net/InetAddress;I)V 515 */ 516 JNIEXPORT void JNICALL 517 Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this, 518 jobject iaObj, jint localport) { 519 520 /* fdObj is the FileDescriptor field on this */ 521 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 522 /* fd is an int field on fdObj */ 523 int fd; 524 int len; 525 SOCKADDR him; 526 527 if (IS_NULL(fdObj)) { 528 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 529 "Socket closed"); 530 return; 531 } else { 532 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 533 } 534 if (IS_NULL(iaObj)) { 535 JNU_ThrowNullPointerException(env, "iaObj is null."); 536 return; 537 } 538 539 /* bind */ 540 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, 541 &len, JNI_TRUE) != 0) { 542 return; 543 } 544 setDefaultScopeID(env, (struct sockaddr *)&him); 545 546 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) { 547 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 548 errno == EPERM || errno == EACCES) { 549 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException", 550 "Bind failed"); 551 } else { 552 JNU_ThrowByNameWithMessageAndLastError 553 (env, JNU_JAVANETPKG "SocketException", "Bind failed"); 554 } 555 return; 556 } 557 558 /* set the address */ 559 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 560 561 /* initialize the local port */ 562 if (localport == 0) { 563 socklen_t slen = sizeof(him); 564 /* Now that we're a connected socket, let's extract the port number 565 * that the system chose for us and store it in the Socket object. 566 */ 567 if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) { 568 JNU_ThrowByNameWithMessageAndLastError 569 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 570 return; 571 } 572 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him); 573 (*env)->SetIntField(env, this, psi_localportID, localport); 574 } else { 575 (*env)->SetIntField(env, this, psi_localportID, localport); 576 } 577 } 578 579 /* 580 * Class: java_net_PlainSocketImpl 581 * Method: socketListen 582 * Signature: (I)V 583 */ 584 JNIEXPORT void JNICALL 585 Java_java_net_PlainSocketImpl_socketListen(JNIEnv *env, jobject this, 586 jint count) 587 { 588 /* this FileDescriptor fd field */ 589 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 590 /* fdObj's int fd field */ 591 int fd; 592 593 if (IS_NULL(fdObj)) { 594 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 595 "Socket closed"); 596 return; 597 } else { 598 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 599 } 600 601 /* 602 * Workaround for bugid 4101691 in Solaris 2.6. See 4106600. 603 * If listen backlog is Integer.MAX_VALUE then subtract 1. 604 */ 605 if (count == 0x7fffffff) 606 count -= 1; 607 608 if (listen(fd, count) == -1) { 609 JNU_ThrowByNameWithMessageAndLastError 610 (env, JNU_JAVANETPKG "SocketException", "Listen failed"); 611 } 612 } 613 614 /* 615 * Class: java_net_PlainSocketImpl 616 * Method: socketAccept 617 * Signature: (Ljava/net/SocketImpl;)V 618 */ 619 JNIEXPORT void JNICALL 620 Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 621 jobject socket) 622 { 623 /* fields on this */ 624 int port; 625 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID); 626 jlong prevTime = 0; 627 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 628 629 /* the FileDescriptor field on socket */ 630 jobject socketFdObj; 631 /* the InetAddress field on socket */ 632 jobject socketAddressObj; 633 634 /* the ServerSocket fd int field on fdObj */ 635 jint fd; 636 637 /* accepted fd */ 638 jint newfd; 639 640 SOCKADDR him; 641 socklen_t slen = SOCKADDR_LEN; 642 643 if (IS_NULL(fdObj)) { 644 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 645 "Socket closed"); 646 return; 647 } else { 648 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 649 } 650 if (IS_NULL(socket)) { 651 JNU_ThrowNullPointerException(env, "socket is null"); 652 return; 653 } 654 655 /* 656 * accept connection but ignore ECONNABORTED indicating that 657 * connection was eagerly accepted by the OS but was reset 658 * before accept() was called. 659 * 660 * If accept timeout in place and timeout is adjusted with 661 * each ECONNABORTED or EWOULDBLOCK to ensure that semantics 662 * of timeout are preserved. 663 */ 664 for (;;) { 665 int ret; 666 667 /* first usage pick up current time */ 668 if (prevTime == 0 && timeout > 0) { 669 prevTime = JVM_CurrentTimeMillis(env, 0); 670 } 671 672 /* passing a timeout of 0 to poll will return immediately, 673 but in the case of ServerSocket 0 means infinite. */ 674 if (timeout <= 0) { 675 ret = NET_Timeout(fd, -1); 676 } else { 677 ret = NET_Timeout(fd, timeout); 678 } 679 if (ret == 0) { 680 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 681 "Accept timed out"); 682 return; 683 } else if (ret == -1) { 684 if (errno == EBADF) { 685 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 686 } else if (errno == ENOMEM) { 687 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 688 } else { 689 JNU_ThrowByNameWithMessageAndLastError 690 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 691 } 692 return; 693 } 694 695 newfd = NET_Accept(fd, (struct sockaddr *)&him, &slen); 696 697 /* connection accepted */ 698 if (newfd >= 0) { 699 SET_BLOCKING(newfd); 700 break; 701 } 702 703 /* non (ECONNABORTED or EWOULDBLOCK) error */ 704 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) { 705 break; 706 } 707 708 /* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */ 709 if (timeout) { 710 jlong currTime = JVM_CurrentTimeMillis(env, 0); 711 timeout -= (currTime - prevTime); 712 713 if (timeout <= 0) { 714 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 715 "Accept timed out"); 716 return; 717 } 718 prevTime = currTime; 719 } 720 } 721 722 if (newfd < 0) { 723 if (newfd == -2) { 724 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 725 "operation interrupted"); 726 } else { 727 if (errno == EINVAL) { 728 errno = EBADF; 729 } 730 if (errno == EBADF) { 731 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 732 } else { 733 JNU_ThrowByNameWithMessageAndLastError 734 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 735 } 736 } 737 return; 738 } 739 740 /* 741 * fill up the remote peer port and address in the new socket structure. 742 */ 743 socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 744 if (socketAddressObj == NULL) { 745 /* should be pending exception */ 746 close(newfd); 747 return; 748 } 749 750 /* 751 * Populate SocketImpl.fd.fd 752 */ 753 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 754 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 755 756 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 757 (*env)->SetIntField(env, socket, psi_portID, port); 758 /* also fill up the local port information */ 759 port = (*env)->GetIntField(env, this, psi_localportID); 760 (*env)->SetIntField(env, socket, psi_localportID, port); 761 } 762 763 764 /* 765 * Class: java_net_PlainSocketImpl 766 * Method: socketAvailable 767 * Signature: ()I 768 */ 769 JNIEXPORT jint JNICALL 770 Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) { 771 772 jint ret = -1; 773 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 774 jint fd; 775 776 if (IS_NULL(fdObj)) { 777 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 778 "Socket closed"); 779 return -1; 780 } else { 781 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 782 } 783 /* NET_SocketAvailable returns 0 for failure, 1 for success */ 784 if (NET_SocketAvailable(fd, &ret) == 0){ 785 if (errno == ECONNRESET) { 786 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 787 } else { 788 JNU_ThrowByNameWithMessageAndLastError 789 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 790 } 791 } 792 return ret; 793 } 794 795 /* 796 * Class: java_net_PlainSocketImpl 797 * Method: socketClose0 798 * Signature: (Z)V 799 */ 800 JNIEXPORT void JNICALL 801 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 802 jboolean useDeferredClose) { 803 804 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 805 jint fd; 806 807 if (IS_NULL(fdObj)) { 808 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 809 "socket already closed"); 810 return; 811 } else { 812 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 813 } 814 if (fd != -1) { 815 if (useDeferredClose && marker_fd >= 0) { 816 NET_Dup2(marker_fd, fd); 817 } else { 818 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 819 NET_SocketClose(fd); 820 } 821 } 822 } 823 824 /* 825 * Class: java_net_PlainSocketImpl 826 * Method: socketShutdown 827 * Signature: (I)V 828 */ 829 JNIEXPORT void JNICALL 830 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 831 jint howto) 832 { 833 834 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 835 jint fd; 836 837 /* 838 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 839 * -1 already? 840 */ 841 if (IS_NULL(fdObj)) { 842 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 843 "socket already closed"); 844 return; 845 } else { 846 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 847 } 848 shutdown(fd, howto); 849 } 850 851 852 /* 853 * Class: java_net_PlainSocketImpl 854 * Method: socketSetOption0 855 * Signature: (IZLjava/lang/Object;)V 856 */ 857 JNIEXPORT void JNICALL 858 Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this, 859 jint cmd, jboolean on, 860 jobject value) { 861 int fd; 862 int level, optname, optlen; 863 union { 864 int i; 865 struct linger ling; 866 } optval; 867 868 /* 869 * Check that socket hasn't been closed 870 */ 871 fd = getFD(env, this); 872 if (fd < 0) { 873 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 874 "Socket closed"); 875 return; 876 } 877 878 /* 879 * SO_TIMEOUT is a NOOP on Solaris/Linux 880 */ 881 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 882 return; 883 } 884 885 /* 886 * Map the Java level socket option to the platform specific 887 * level and option name. 888 */ 889 if (NET_MapSocketOption(cmd, &level, &optname)) { 890 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 891 return; 892 } 893 894 switch (cmd) { 895 case java_net_SocketOptions_SO_SNDBUF : 896 case java_net_SocketOptions_SO_RCVBUF : 897 case java_net_SocketOptions_SO_LINGER : 898 case java_net_SocketOptions_IP_TOS : 899 { 900 jclass cls; 901 jfieldID fid; 902 903 cls = (*env)->FindClass(env, "java/lang/Integer"); 904 CHECK_NULL(cls); 905 fid = (*env)->GetFieldID(env, cls, "value", "I"); 906 CHECK_NULL(fid); 907 908 if (cmd == java_net_SocketOptions_SO_LINGER) { 909 if (on) { 910 optval.ling.l_onoff = 1; 911 optval.ling.l_linger = (*env)->GetIntField(env, value, fid); 912 } else { 913 optval.ling.l_onoff = 0; 914 optval.ling.l_linger = 0; 915 } 916 optlen = sizeof(optval.ling); 917 } else { 918 optval.i = (*env)->GetIntField(env, value, fid); 919 optlen = sizeof(optval.i); 920 } 921 922 break; 923 } 924 925 /* Boolean -> int */ 926 default : 927 optval.i = (on ? 1 : 0); 928 optlen = sizeof(optval.i); 929 930 } 931 932 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 933 #if defined(__solaris__) || defined(_AIX) 934 if (errno == EINVAL) { 935 // On Solaris setsockopt will set errno to EINVAL if the socket 936 // is closed. The default error message is then confusing 937 char fullMsg[128]; 938 jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer"); 939 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); 940 return; 941 } 942 #endif /* __solaris__ */ 943 JNU_ThrowByNameWithMessageAndLastError 944 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 945 } 946 } 947 948 /* 949 * Class: java_net_PlainSocketImpl 950 * Method: socketGetOption 951 * Signature: (I)I 952 */ 953 JNIEXPORT jint JNICALL 954 Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this, 955 jint cmd, jobject iaContainerObj) { 956 957 int fd; 958 int level, optname, optlen; 959 union { 960 int i; 961 struct linger ling; 962 } optval; 963 964 /* 965 * Check that socket hasn't been closed 966 */ 967 fd = getFD(env, this); 968 if (fd < 0) { 969 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 970 "Socket closed"); 971 return -1; 972 } 973 974 /* 975 * SO_BINDADDR isn't a socket option 976 */ 977 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 978 SOCKADDR him; 979 socklen_t len = 0; 980 int port; 981 jobject iaObj; 982 jclass iaCntrClass; 983 jfieldID iaFieldID; 984 985 len = SOCKADDR_LEN; 986 987 if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) { 988 JNU_ThrowByNameWithMessageAndLastError 989 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 990 return -1; 991 } 992 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 993 CHECK_NULL_RETURN(iaObj, -1); 994 995 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 996 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 997 CHECK_NULL_RETURN(iaFieldID, -1); 998 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 999 return 0; /* notice change from before */ 1000 } 1001 1002 /* 1003 * Map the Java level socket option to the platform specific 1004 * level and option name. 1005 */ 1006 if (NET_MapSocketOption(cmd, &level, &optname)) { 1007 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1008 return -1; 1009 } 1010 1011 /* 1012 * Args are int except for SO_LINGER 1013 */ 1014 if (cmd == java_net_SocketOptions_SO_LINGER) { 1015 optlen = sizeof(optval.ling); 1016 } else { 1017 optlen = sizeof(optval.i); 1018 } 1019 1020 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 1021 JNU_ThrowByNameWithMessageAndLastError 1022 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 1023 return -1; 1024 } 1025 1026 switch (cmd) { 1027 case java_net_SocketOptions_SO_LINGER: 1028 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 1029 1030 case java_net_SocketOptions_SO_SNDBUF: 1031 case java_net_SocketOptions_SO_RCVBUF: 1032 case java_net_SocketOptions_IP_TOS: 1033 return optval.i; 1034 1035 default : 1036 return (optval.i == 0) ? -1 : 1; 1037 } 1038 } 1039 1040 1041 /* 1042 * Class: java_net_PlainSocketImpl 1043 * Method: socketSendUrgentData 1044 * Signature: (B)V 1045 */ 1046 JNIEXPORT void JNICALL 1047 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 1048 jint data) { 1049 /* The fd field */ 1050 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1051 int n, fd; 1052 unsigned char d = data & 0xFF; 1053 1054 if (IS_NULL(fdObj)) { 1055 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1056 return; 1057 } else { 1058 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1059 /* Bug 4086704 - If the Socket associated with this file descriptor 1060 * was closed (sysCloseFD), the file descriptor is set to -1. 1061 */ 1062 if (fd == -1) { 1063 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1064 return; 1065 } 1066 1067 } 1068 n = NET_Send(fd, (char *)&d, 1, MSG_OOB); 1069 if (n == -1) { 1070 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 1071 } 1072 }