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