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