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 <windows.h> 27 #include <winsock2.h> 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <malloc.h> 32 #include <sys/types.h> 33 34 #include "java_net_SocketOptions.h" 35 #include "java_net_TwoStacksPlainSocketImpl.h" 36 #include "java_net_SocketImpl.h" 37 #include "java_net_InetAddress.h" 38 #include "java_io_FileDescriptor.h" 39 #include "java_lang_Integer.h" 40 41 #include "jvm.h" 42 #include "net_util.h" 43 #include "jni_util.h" 44 45 /************************************************************************ 46 * TwoStacksPlainSocketImpl 47 */ 48 49 static jfieldID IO_fd_fdID; 50 51 jfieldID psi_fdID; 52 jfieldID psi_fd1ID; 53 jfieldID psi_addressID; 54 jfieldID psi_portID; 55 jfieldID psi_localportID; 56 jfieldID psi_timeoutID; 57 jfieldID psi_trafficClassID; 58 jfieldID psi_serverSocketID; 59 jfieldID psi_lastfdID; 60 61 /* 62 * the level of the TCP protocol for setsockopt and getsockopt 63 * we only want to look this up once, from the static initializer 64 * of TwoStacksPlainSocketImpl 65 */ 66 static int tcp_level = -1; 67 68 static int getFD(JNIEnv *env, jobject this) { 69 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 70 71 if (fdObj == NULL) { 72 return -1; 73 } 74 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 75 } 76 77 static int getFD1(JNIEnv *env, jobject this) { 78 jobject fdObj = (*env)->GetObjectField(env, this, psi_fd1ID); 79 80 if (fdObj == NULL) { 81 return -1; 82 } 83 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 84 } 85 86 87 /* 88 * The initProto function is called whenever TwoStacksPlainSocketImpl is 89 * loaded, to cache fieldIds for efficiency. This is called everytime 90 * the Java class is loaded. 91 * 92 * Class: java_net_TwoStacksPlainSocketImpl 93 * Method: initProto 94 95 * Signature: ()V 96 */ 97 JNIEXPORT void JNICALL 98 Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) { 99 100 struct protoent *proto = getprotobyname("TCP"); 101 tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto); 102 103 psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;"); 104 CHECK_NULL(psi_fdID); 105 psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;"); 106 CHECK_NULL(psi_fd1ID); 107 psi_addressID = (*env)->GetFieldID(env, cls, "address", 108 "Ljava/net/InetAddress;"); 109 CHECK_NULL(psi_addressID); 110 psi_portID = (*env)->GetFieldID(env, cls, "port", "I"); 111 CHECK_NULL(psi_portID); 112 psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I"); 113 CHECK_NULL(psi_portID); 114 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I"); 115 CHECK_NULL(psi_localportID); 116 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); 117 CHECK_NULL(psi_timeoutID); 118 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); 119 CHECK_NULL(psi_trafficClassID); 120 psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket", 121 "Ljava/net/ServerSocket;"); 122 CHECK_NULL(psi_serverSocketID); 123 IO_fd_fdID = NET_GetFileDescriptorID(env); 124 CHECK_NULL(IO_fd_fdID); 125 } 126 127 /* 128 * Class: java_net_TwoStacksPlainSocketImpl 129 * Method: socketCreate 130 * Signature: (Z)V 131 */ 132 JNIEXPORT void JNICALL 133 Java_java_net_TwoStacksPlainSocketImpl_socketCreate(JNIEnv *env, jobject this, 134 jboolean stream) { 135 jobject fdObj, fd1Obj; 136 int fd, fd1; 137 138 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 139 140 if (IS_NULL(fdObj)) { 141 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 142 "null fd object"); 143 return; 144 } 145 fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); 146 if (fd == -1) { 147 NET_ThrowCurrent(env, "create"); 148 return; 149 } else { 150 /* Set socket attribute so it is not passed to any child process */ 151 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 152 (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd); 153 } 154 if (ipv6_available()) { 155 fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 156 157 if (IS_NULL(fd1Obj)) { 158 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 159 "null fd1 object"); 160 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 161 NET_SocketClose(fd); 162 return; 163 } 164 fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); 165 if (fd1 == -1) { 166 NET_ThrowCurrent(env, "create"); 167 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 168 NET_SocketClose(fd); 169 return; 170 } else { 171 /* Set socket attribute so it is not passed to any child process */ 172 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE); 173 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1); 174 } 175 } else { 176 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 177 } 178 } 179 180 /* 181 * inetAddress is the address object passed to the socket connect 182 * call. 183 * 184 * Class: java_net_TwoStacksPlainSocketImpl 185 * Method: socketConnect 186 * Signature: (Ljava/net/InetAddress;I)V 187 */ 188 JNIEXPORT void JNICALL 189 Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this, 190 jobject iaObj, jint port, 191 jint timeout) 192 { 193 jint localport = (*env)->GetIntField(env, this, psi_localportID); 194 195 /* family and localport are int fields of iaObj */ 196 int family; 197 jint fd, fd1=-1; 198 jint len; 199 int ipv6_supported = ipv6_available(); 200 201 /* fd initially points to the IPv4 socket and fd1 to the IPv6 socket 202 * If we want to connect to IPv6 then we swap the two sockets/objects 203 * This way, fd is always the connected socket, and fd1 always gets closed. 204 */ 205 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 206 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 207 208 SOCKETADDRESS him; 209 210 /* The result of the connection */ 211 int connect_res; 212 213 if (!IS_NULL(fdObj)) { 214 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 215 } 216 217 if (ipv6_supported && !IS_NULL(fd1Obj)) { 218 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 219 } 220 221 if (IS_NULL(iaObj)) { 222 JNU_ThrowNullPointerException(env, "inet address argument is null."); 223 return; 224 } 225 226 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_FALSE) != 0) { 227 return; 228 } 229 230 family = him.him.sa_family; 231 if (family == AF_INET6) { 232 if (!ipv6_supported) { 233 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 234 "Protocol family not supported"); 235 return; 236 } else { 237 if (fd1 == -1) { 238 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 239 "Destination unreachable"); 240 return; 241 } 242 /* close the v4 socket, and set fd to be the v6 socket */ 243 (*env)->SetObjectField(env, this, psi_fdID, fd1Obj); 244 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 245 NET_SocketClose(fd); 246 fd = fd1; fdObj = fd1Obj; 247 } 248 } else { 249 if (fd1 != -1) { 250 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1); 251 NET_SocketClose(fd1); 252 } 253 if (fd == -1) { 254 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 255 "Destination unreachable"); 256 return; 257 } 258 } 259 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 260 261 if (timeout <= 0) { 262 connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him)); 263 if (connect_res == SOCKET_ERROR) { 264 connect_res = WSAGetLastError(); 265 } 266 } else { 267 int optval; 268 int optlen = sizeof(optval); 269 270 /* make socket non-blocking */ 271 optval = 1; 272 ioctlsocket( fd, FIONBIO, &optval ); 273 274 /* initiate the connect */ 275 connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him)); 276 if (connect_res == SOCKET_ERROR) { 277 if (WSAGetLastError() != WSAEWOULDBLOCK) { 278 connect_res = WSAGetLastError(); 279 } else { 280 fd_set wr, ex; 281 struct timeval t; 282 283 FD_ZERO(&wr); 284 FD_ZERO(&ex); 285 FD_SET(fd, &wr); 286 FD_SET(fd, &ex); 287 t.tv_sec = timeout / 1000; 288 t.tv_usec = (timeout % 1000) * 1000; 289 290 /* 291 * Wait for timout, connection established or 292 * connection failed. 293 */ 294 connect_res = select(fd+1, 0, &wr, &ex, &t); 295 296 /* 297 * Timeout before connection is established/failed so 298 * we throw exception and shutdown input/output to prevent 299 * socket from being used. 300 * The socket should be closed immediately by the caller. 301 */ 302 if (connect_res == 0) { 303 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 304 "connect timed out"); 305 shutdown( fd, SD_BOTH ); 306 307 /* make socket blocking again - just in case */ 308 optval = 0; 309 ioctlsocket( fd, FIONBIO, &optval ); 310 return; 311 } 312 313 /* 314 * We must now determine if the connection has been established 315 * or if it has failed. The logic here is designed to work around 316 * bug on Windows NT whereby using getsockopt to obtain the 317 * last error (SO_ERROR) indicates there is no error. The workaround 318 * on NT is to allow winsock to be scheduled and this is done by 319 * yielding and retrying. As yielding is problematic in heavy 320 * load conditions we attempt up to 3 times to get the error reason. 321 */ 322 if (!FD_ISSET(fd, &ex)) { 323 connect_res = 0; 324 } else { 325 int retry; 326 for (retry=0; retry<3; retry++) { 327 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, 328 (char*)&connect_res, &optlen); 329 if (connect_res) { 330 break; 331 } 332 Sleep(0); 333 } 334 335 if (connect_res == 0) { 336 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 337 "Unable to establish connection"); 338 return; 339 } 340 } 341 } 342 } 343 344 /* make socket blocking again */ 345 optval = 0; 346 ioctlsocket(fd, FIONBIO, &optval); 347 } 348 349 if (connect_res) { 350 if (connect_res == WSAEADDRNOTAVAIL) { 351 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 352 "connect: Address is invalid on local machine, or port is not valid on remote machine"); 353 } else { 354 NET_ThrowNew(env, connect_res, "connect"); 355 } 356 return; 357 } 358 359 (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd); 360 361 /* set the remote peer address and port */ 362 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 363 (*env)->SetIntField(env, this, psi_portID, port); 364 365 /* 366 * we need to initialize the local port field if bind was called 367 * previously to the connect (by the client) then localport field 368 * will already be initialized 369 */ 370 if (localport == 0) { 371 /* Now that we're a connected socket, let's extract the port number 372 * that the system chose for us and store it in the Socket object. 373 */ 374 u_short port; 375 int len = SOCKETADDRESS_LEN(&him); 376 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { 377 378 if (WSAGetLastError() == WSAENOTSOCK) { 379 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 380 "Socket closed"); 381 } else { 382 NET_ThrowCurrent(env, "getsockname failed"); 383 } 384 return; 385 } 386 port = ntohs ((u_short)GET_PORT(&him)); 387 (*env)->SetIntField(env, this, psi_localportID, (int) port); 388 } 389 } 390 391 /* 392 * Class: java_net_TwoStacksPlainSocketImpl 393 * Method: socketBind 394 * Signature: (Ljava/net/InetAddress;I)V 395 */ 396 JNIEXPORT void JNICALL 397 Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, 398 jobject iaObj, jint localport) { 399 400 /* fdObj is the FileDescriptor field on this */ 401 jobject fdObj, fd1Obj; 402 /* fd is an int field on fdObj */ 403 int fd, fd1, len; 404 int ipv6_supported = ipv6_available(); 405 406 /* family is an int field of iaObj */ 407 int family; 408 int rv; 409 410 SOCKETADDRESS him; 411 412 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 413 fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 414 415 family = (*env)->GetIntField(env, iaObj, ia_familyID); 416 417 if (family == IPv6 && !ipv6_supported) { 418 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 419 "Protocol family not supported"); 420 return; 421 } 422 423 if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) { 424 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 425 "Socket closed"); 426 return; 427 } else { 428 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 429 if (ipv6_supported) { 430 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 431 } 432 } 433 if (IS_NULL(iaObj)) { 434 JNU_ThrowNullPointerException(env, "inet address argument"); 435 return; 436 } 437 438 if (NET_InetAddressToSockaddr(env, iaObj, localport, 439 (struct sockaddr *)&him, &len, JNI_FALSE) != 0) { 440 return; 441 } 442 443 if (ipv6_supported) { 444 struct ipv6bind v6bind; 445 v6bind.addr = &him; 446 v6bind.ipv4_fd = fd; 447 v6bind.ipv6_fd = fd1; 448 rv = NET_BindV6(&v6bind); 449 if (rv != -1) { 450 /* check if the fds have changed */ 451 if (v6bind.ipv4_fd != fd) { 452 fd = v6bind.ipv4_fd; 453 if (fd == -1) { 454 /* socket is closed. */ 455 (*env)->SetObjectField(env, this, psi_fdID, NULL); 456 } else { 457 /* socket was re-created */ 458 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 459 } 460 } 461 if (v6bind.ipv6_fd != fd1) { 462 fd1 = v6bind.ipv6_fd; 463 if (fd1 == -1) { 464 /* socket is closed. */ 465 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 466 } else { 467 /* socket was re-created */ 468 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1); 469 } 470 } 471 } 472 } else { 473 rv = NET_Bind(fd, (struct sockaddr *)&him, len); 474 } 475 476 if (rv == -1) { 477 NET_ThrowCurrent(env, "JVM_Bind"); 478 return; 479 } 480 481 /* set the address */ 482 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 483 484 /* intialize the local port */ 485 if (localport == 0) { 486 /* Now that we're a bound socket, let's extract the port number 487 * that the system chose for us and store it in the Socket object. 488 */ 489 int len = SOCKETADDRESS_LEN(&him); 490 u_short port; 491 fd = him.him.sa_family == AF_INET? fd: fd1; 492 493 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { 494 NET_ThrowCurrent(env, "getsockname in plain socketBind"); 495 return; 496 } 497 port = ntohs ((u_short) GET_PORT (&him)); 498 499 (*env)->SetIntField(env, this, psi_localportID, (int) port); 500 } else { 501 (*env)->SetIntField(env, this, psi_localportID, localport); 502 } 503 } 504 505 /* 506 * Class: java_net_TwoStacksPlainSocketImpl 507 * Method: socketListen 508 * Signature: (I)V 509 */ 510 JNIEXPORT void JNICALL 511 Java_java_net_TwoStacksPlainSocketImpl_socketListen (JNIEnv *env, jobject this, 512 jint count) 513 { 514 /* this FileDescriptor fd field */ 515 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 516 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 517 jobject address; 518 /* fdObj's int fd field */ 519 int fd, fd1; 520 SOCKETADDRESS addr; int addrlen; 521 522 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 523 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 524 "socket closed"); 525 return; 526 } 527 528 if (!IS_NULL(fdObj)) { 529 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 530 } 531 /* Listen on V4 if address type is v4 or if v6 and address is ::0. 532 * Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0. 533 * In cases, where we listen on one space only, we close the other socket. 534 */ 535 address = (*env)->GetObjectField(env, this, psi_addressID); 536 if (IS_NULL(address)) { 537 JNU_ThrowNullPointerException(env, "socket address"); 538 return; 539 } 540 if (NET_InetAddressToSockaddr(env, address, 0, (struct sockaddr *)&addr, 541 &addrlen, JNI_FALSE) != 0) { 542 return; 543 } 544 545 if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(&addr.him6)) { 546 /* listen on v4 */ 547 if (listen(fd, count) == -1) { 548 NET_ThrowCurrent(env, "listen failed"); 549 } 550 } else { 551 NET_SocketClose (fd); 552 (*env)->SetObjectField(env, this, psi_fdID, NULL); 553 } 554 if (ipv6_available() && !IS_NULL(fd1Obj)) { 555 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 556 if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) { 557 /* listen on v6 */ 558 if (listen(fd1, count) == -1) { 559 NET_ThrowCurrent(env, "listen failed"); 560 } 561 } else { 562 NET_SocketClose (fd1); 563 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 564 } 565 } 566 } 567 568 /* 569 * Class: java_net_TwoStacksPlainSocketImpl 570 * Method: socketAccept 571 * Signature: (Ljava/net/SocketImpl;)V 572 */ 573 JNIEXPORT void JNICALL 574 Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 575 jobject socket) 576 { 577 /* fields on this */ 578 jint port; 579 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID); 580 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 581 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 582 583 /* the FileDescriptor field on socket */ 584 jobject socketFdObj; 585 586 /* cache the Inet4/6Address classes */ 587 static jclass inet4Cls; 588 static jclass inet6Cls; 589 590 /* the InetAddress field on socket */ 591 jobject socketAddressObj; 592 593 /* the fd int field on fdObj */ 594 jint fd=-1, fd1=-1; 595 596 SOCKETADDRESS him; 597 jint len; 598 599 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 600 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 601 "Socket closed"); 602 return; 603 } 604 if (!IS_NULL(fdObj)) { 605 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 606 } 607 if (!IS_NULL(fd1Obj)) { 608 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 609 } 610 if (IS_NULL(socket)) { 611 JNU_ThrowNullPointerException(env, "socket is null"); 612 return; 613 } else { 614 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 615 socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID); 616 } 617 if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) { 618 JNU_ThrowNullPointerException(env, "socket address or fd obj"); 619 return; 620 } 621 if (fd != -1 && fd1 != -1) { 622 fd_set rfds; 623 struct timeval t, *tP=&t; 624 int lastfd, res, fd2; 625 FD_ZERO(&rfds); 626 FD_SET(fd,&rfds); 627 FD_SET(fd1,&rfds); 628 if (timeout) { 629 t.tv_sec = timeout/1000; 630 t.tv_usec = (timeout%1000)*1000; 631 } else { 632 tP = NULL; 633 } 634 res = select (fd, &rfds, NULL, NULL, tP); 635 if (res == 0) { 636 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 637 "Accept timed out"); 638 return; 639 } else if (res == 1) { 640 fd2 = FD_ISSET(fd, &rfds)? fd: fd1; 641 } else if (res == 2) { 642 /* avoid starvation */ 643 lastfd = (*env)->GetIntField(env, this, psi_lastfdID); 644 if (lastfd != -1) { 645 fd2 = lastfd==fd? fd1: fd; 646 } else { 647 fd2 = fd; 648 } 649 (*env)->SetIntField(env, this, psi_lastfdID, fd2); 650 } else { 651 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 652 "select failed"); 653 return; 654 } 655 if (fd2 == fd) { /* v4 */ 656 len = sizeof (struct sockaddr_in); 657 } else { 658 len = sizeof (struct SOCKADDR_IN6); 659 } 660 fd = fd2; 661 } else { 662 int ret; 663 if (fd1 != -1) { 664 fd = fd1; 665 len = sizeof (struct SOCKADDR_IN6); 666 } else { 667 len = sizeof (struct sockaddr_in); 668 } 669 if (timeout) { 670 ret = NET_Timeout(fd, timeout); 671 if (ret == 0) { 672 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 673 "Accept timed out"); 674 return; 675 } else if (ret == -1) { 676 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 677 /* REMIND: SOCKET CLOSED PROBLEM */ 678 /* NET_ThrowCurrent(env, "Accept failed"); */ 679 return; 680 } else if (ret == -2) { 681 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 682 "operation interrupted"); 683 return; 684 } 685 } 686 } 687 fd = accept(fd, (struct sockaddr *)&him, &len); 688 if (fd < 0) { 689 /* REMIND: SOCKET CLOSED PROBLEM */ 690 if (fd == -2) { 691 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 692 "operation interrupted"); 693 } else { 694 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 695 "socket closed"); 696 } 697 return; 698 } 699 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd); 700 701 if (him.him.sa_family == AF_INET) { 702 if (inet4Cls == NULL) { 703 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 704 if (c != NULL) { 705 inet4Cls = (*env)->NewGlobalRef(env, c); 706 (*env)->DeleteLocalRef(env, c); 707 } 708 } 709 710 /* 711 * fill up the remote peer port and address in the new socket structure 712 */ 713 if (inet4Cls != NULL) { 714 socketAddressObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 715 } else { 716 socketAddressObj = NULL; 717 } 718 if (socketAddressObj == NULL) { 719 /* 720 * FindClass or NewObject failed so close connection and 721 * exist (there will be a pending exception). 722 */ 723 NET_SocketClose(fd); 724 return; 725 } 726 727 (*env)->SetIntField(env, socketAddressObj, ia_addressID, 728 ntohl(him.him4.sin_addr.s_addr)); 729 (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv4); 730 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 731 } else { 732 jbyteArray addr; 733 /* AF_INET6 -> Inet6Address */ 734 if (inet6Cls == 0) { 735 jclass c = (*env)->FindClass(env, "java/net/Inet6Address"); 736 if (c != NULL) { 737 inet6Cls = (*env)->NewGlobalRef(env, c); 738 (*env)->DeleteLocalRef(env, c); 739 } 740 } 741 742 if (inet6Cls != NULL) { 743 socketAddressObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID); 744 } else { 745 socketAddressObj = NULL; 746 } 747 if (socketAddressObj == NULL) { 748 /* 749 * FindClass or NewObject failed so close connection and 750 * exist (there will be a pending exception). 751 */ 752 NET_SocketClose(fd); 753 return; 754 } 755 addr = (*env)->GetObjectField (env, socketAddressObj, ia6_ipaddressID); 756 (*env)->SetByteArrayRegion (env, addr, 0, 16, (const char *)&him.him6.sin6_addr); 757 (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv6); 758 (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, him.him6.sin6_scope_id); 759 } 760 /* fields common to AF_INET and AF_INET6 */ 761 762 port = ntohs ((u_short) GET_PORT (&him)); 763 (*env)->SetIntField(env, socket, psi_portID, (int)port); 764 port = (*env)->GetIntField(env, this, psi_localportID); 765 (*env)->SetIntField(env, socket, psi_localportID, port); 766 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 767 } 768 769 /* 770 * Class: java_net_TwoStacksPlainSocketImpl 771 * Method: socketAvailable 772 * Signature: ()I 773 */ 774 JNIEXPORT jint JNICALL 775 Java_java_net_TwoStacksPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) { 776 777 jint available = -1; 778 jint res; 779 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 780 jint fd; 781 782 if (IS_NULL(fdObj)) { 783 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 784 return -1; 785 } else { 786 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 787 } 788 res = ioctlsocket(fd, FIONREAD, &available); 789 /* if result isn't 0, it means an error */ 790 if (res != 0) { 791 NET_ThrowNew(env, res, "socket available"); 792 } 793 return available; 794 } 795 796 /* 797 * Class: java_net_TwoStacksPlainSocketImpl 798 * Method: socketClose 799 * Signature: ()V 800 */ 801 JNIEXPORT void JNICALL 802 Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 803 jboolean useDeferredClose) { 804 805 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 806 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 807 jint fd=-1, fd1=-1; 808 809 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 810 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 811 "socket already closed"); 812 return; 813 } 814 if (!IS_NULL(fdObj)) { 815 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 816 } 817 if (!IS_NULL(fd1Obj)) { 818 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 819 } 820 if (fd != -1) { 821 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 822 NET_SocketClose(fd); 823 } 824 if (fd1 != -1) { 825 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1); 826 NET_SocketClose(fd1); 827 } 828 } 829 830 /* 831 * Socket options for plainsocketImpl 832 * 833 * 834 * Class: java_net_TwoStacksPlainSocketImpl 835 * Method: socketSetOption 836 * Signature: (IZLjava/lang/Object;)V 837 */ 838 JNIEXPORT void JNICALL 839 Java_java_net_TwoStacksPlainSocketImpl_socketSetOption(JNIEnv *env, jobject this, 840 jint cmd, jboolean on, 841 jobject value) { 842 int fd, fd1; 843 int level, optname, optlen; 844 union { 845 int i; 846 struct linger ling; 847 } optval; 848 849 /* 850 * Get SOCKET and check that it hasn't been closed 851 */ 852 fd = getFD(env, this); 853 fd1 = getFD1(env, this); 854 if (fd < 0 && fd1 < 0) { 855 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 856 return; 857 } 858 859 /* 860 * SO_TIMEOUT is the socket option used to specify the timeout 861 * for ServerSocket.accept and Socket.getInputStream().read. 862 * It does not typically map to a native level socket option. 863 * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO 864 * socket option to specify a receive timeout on the socket. This 865 * receive timeout is applicable to Socket only and the socket 866 * option should not be set on ServerSocket. 867 */ 868 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 869 870 /* 871 * Don't enable the socket option on ServerSocket as it's 872 * meaningless (we don't receive on a ServerSocket). 873 */ 874 jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID); 875 if (ssObj != NULL) { 876 return; 877 } 878 879 /* 880 * SO_RCVTIMEO is only supported on Microsoft's implementation 881 * of Windows Sockets so if WSAENOPROTOOPT returned then 882 * reset flag and timeout will be implemented using 883 * select() -- see SocketInputStream.socketRead. 884 */ 885 if (isRcvTimeoutSupported) { 886 jclass iCls = (*env)->FindClass(env, "java/lang/Integer"); 887 jfieldID i_valueID; 888 jint timeout; 889 890 CHECK_NULL(iCls); 891 i_valueID = (*env)->GetFieldID(env, iCls, "value", "I"); 892 CHECK_NULL(i_valueID); 893 timeout = (*env)->GetIntField(env, value, i_valueID); 894 895 /* 896 * Disable SO_RCVTIMEO if timeout is <= 5 second. 897 */ 898 if (timeout <= 5000) { 899 timeout = 0; 900 } 901 902 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 903 sizeof(timeout)) < 0) { 904 if (WSAGetLastError() == WSAENOPROTOOPT) { 905 isRcvTimeoutSupported = JNI_FALSE; 906 } else { 907 NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); 908 } 909 } 910 if (fd1 != -1) { 911 if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 912 sizeof(timeout)) < 0) { 913 NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); 914 } 915 } 916 } 917 return; 918 } 919 920 /* 921 * Map the Java level socket option to the platform specific 922 * level 923 */ 924 if (NET_MapSocketOption(cmd, &level, &optname)) { 925 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 926 "Invalid option"); 927 return; 928 } 929 930 switch (cmd) { 931 932 case java_net_SocketOptions_TCP_NODELAY : 933 case java_net_SocketOptions_SO_OOBINLINE : 934 case java_net_SocketOptions_SO_KEEPALIVE : 935 case java_net_SocketOptions_SO_REUSEADDR : 936 optval.i = (on ? 1 : 0); 937 optlen = sizeof(optval.i); 938 break; 939 940 case java_net_SocketOptions_SO_SNDBUF : 941 case java_net_SocketOptions_SO_RCVBUF : 942 case java_net_SocketOptions_IP_TOS : 943 { 944 jclass cls; 945 jfieldID fid; 946 947 cls = (*env)->FindClass(env, "java/lang/Integer"); 948 CHECK_NULL(cls); 949 fid = (*env)->GetFieldID(env, cls, "value", "I"); 950 CHECK_NULL(fid); 951 952 optval.i = (*env)->GetIntField(env, value, fid); 953 optlen = sizeof(optval.i); 954 } 955 break; 956 957 case java_net_SocketOptions_SO_LINGER : 958 { 959 jclass cls; 960 jfieldID fid; 961 962 cls = (*env)->FindClass(env, "java/lang/Integer"); 963 CHECK_NULL(cls); 964 fid = (*env)->GetFieldID(env, cls, "value", "I"); 965 CHECK_NULL(fid); 966 967 if (on) { 968 optval.ling.l_onoff = 1; 969 optval.ling.l_linger = 970 (unsigned short)(*env)->GetIntField(env, value, fid); 971 } else { 972 optval.ling.l_onoff = 0; 973 optval.ling.l_linger = 0; 974 } 975 optlen = sizeof(optval.ling); 976 } 977 break; 978 979 default: /* shouldn't get here */ 980 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 981 "Option not supported by TwoStacksPlainSocketImpl"); 982 return; 983 } 984 985 if (fd != -1) { 986 if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) { 987 NET_ThrowCurrent(env, "setsockopt"); 988 } 989 } 990 991 if (fd1 != -1) { 992 if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) { 993 NET_ThrowCurrent(env, "setsockopt"); 994 } 995 } 996 } 997 998 999 /* 1000 * Class: java_net_TwoStacksPlainSocketImpl 1001 * Method: socketGetOption 1002 * Signature: (I)I 1003 */ 1004 JNIEXPORT jint JNICALL 1005 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this, 1006 jint opt, jobject iaContainerObj) { 1007 1008 int fd, fd1; 1009 int level, optname, optlen; 1010 union { 1011 int i; 1012 struct linger ling; 1013 } optval; 1014 1015 /* 1016 * Get SOCKET and check it hasn't been closed 1017 */ 1018 fd = getFD(env, this); 1019 fd1 = getFD1(env, this); 1020 1021 if (fd < 0 && fd1 < 0) { 1022 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 1023 return -1; 1024 } 1025 if (fd < 0) { 1026 fd = fd1; 1027 } 1028 1029 /* For IPv6, we assume both sockets have the same setting always */ 1030 1031 /* 1032 * SO_BINDADDR isn't a socket option 1033 */ 1034 if (opt == java_net_SocketOptions_SO_BINDADDR) { 1035 SOCKETADDRESS him; 1036 int len; 1037 int port; 1038 jobject iaObj; 1039 jclass iaCntrClass; 1040 jfieldID iaFieldID; 1041 1042 len = sizeof(him); 1043 1044 if (fd == -1) { 1045 /* must be an IPV6 only socket. Case where both sockets are != -1 1046 * is handled in java 1047 */ 1048 fd = getFD1 (env, this); 1049 } 1050 1051 if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) { 1052 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1053 "Error getting socket name"); 1054 return -1; 1055 } 1056 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 1057 CHECK_NULL_RETURN(iaObj, -1); 1058 1059 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 1060 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 1061 CHECK_NULL_RETURN(iaFieldID, -1); 1062 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 1063 return 0; /* notice change from before */ 1064 } 1065 1066 /* 1067 * Map the Java level socket option to the platform specific 1068 * level and option name. 1069 */ 1070 if (NET_MapSocketOption(opt, &level, &optname)) { 1071 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1072 return -1; 1073 } 1074 1075 /* 1076 * Args are int except for SO_LINGER 1077 */ 1078 if (opt == java_net_SocketOptions_SO_LINGER) { 1079 optlen = sizeof(optval.ling); 1080 } else { 1081 optlen = sizeof(optval.i); 1082 optval.i = 0; 1083 } 1084 1085 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 1086 NET_ThrowCurrent(env, "getsockopt"); 1087 return -1; 1088 } 1089 1090 switch (opt) { 1091 case java_net_SocketOptions_SO_LINGER: 1092 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 1093 1094 case java_net_SocketOptions_SO_SNDBUF: 1095 case java_net_SocketOptions_SO_RCVBUF: 1096 case java_net_SocketOptions_IP_TOS: 1097 return optval.i; 1098 1099 case java_net_SocketOptions_TCP_NODELAY : 1100 case java_net_SocketOptions_SO_OOBINLINE : 1101 case java_net_SocketOptions_SO_KEEPALIVE : 1102 case java_net_SocketOptions_SO_REUSEADDR : 1103 return (optval.i == 0) ? -1 : 1; 1104 1105 default: /* shouldn't get here */ 1106 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1107 "Option not supported by TwoStacksPlainSocketImpl"); 1108 return -1; 1109 } 1110 } 1111 1112 /* 1113 * Class: java_net_TwoStacksPlainSocketImpl 1114 * Method: socketShutdown 1115 * Signature: (I)V 1116 */ 1117 JNIEXPORT void JNICALL 1118 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 1119 jint howto) 1120 { 1121 1122 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1123 jint fd; 1124 1125 /* 1126 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 1127 * -1 already? 1128 */ 1129 if (IS_NULL(fdObj)) { 1130 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1131 "socket already closed"); 1132 return; 1133 } else { 1134 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1135 } 1136 shutdown(fd, howto); 1137 } 1138 1139 /* 1140 * Class: java_net_TwoStacksPlainSocketImpl 1141 * Method: socketSendUrgentData 1142 * Signature: (B)V 1143 */ 1144 JNIEXPORT void JNICALL 1145 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 1146 jint data) { 1147 /* The fd field */ 1148 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1149 int n, fd; 1150 unsigned char d = data & 0xff; 1151 1152 if (IS_NULL(fdObj)) { 1153 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1154 return; 1155 } else { 1156 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1157 /* Bug 4086704 - If the Socket associated with this file descriptor 1158 * was closed (sysCloseFD), the the file descriptor is set to -1. 1159 */ 1160 if (fd == -1) { 1161 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1162 return; 1163 } 1164 1165 } 1166 n = send(fd, (char *)&data, 1, MSG_OOB); 1167 if (n == JVM_IO_ERR) { 1168 NET_ThrowCurrent(env, "send"); 1169 return; 1170 } 1171 if (n == JVM_IO_INTR) { 1172 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0); 1173 return; 1174 } 1175 }