1 /* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <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 "net_util.h" 41 #include "jni_util.h" 42 43 /************************************************************************ 44 * TwoStacksPlainSocketImpl 45 */ 46 47 static jfieldID IO_fd_fdID; 48 49 jfieldID psi_fdID; 50 jfieldID psi_fd1ID; 51 jfieldID psi_addressID; 52 jfieldID psi_portID; 53 jfieldID psi_localportID; 54 jfieldID psi_timeoutID; 55 jfieldID psi_trafficClassID; 56 jfieldID psi_serverSocketID; 57 jfieldID psi_lastfdID; 58 59 /* 60 * the level of the TCP protocol for setsockopt and getsockopt 61 * we only want to look this up once, from the static initializer 62 * of TwoStacksPlainSocketImpl 63 */ 64 static int tcp_level = -1; 65 66 static int getFD(JNIEnv *env, jobject this) { 67 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 68 69 if (fdObj == NULL) { 70 return -1; 71 } 72 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 73 } 74 75 static int getFD1(JNIEnv *env, jobject this) { 76 jobject fdObj = (*env)->GetObjectField(env, this, psi_fd1ID); 77 78 if (fdObj == NULL) { 79 return -1; 80 } 81 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 82 } 83 84 85 /* 86 * The initProto function is called whenever TwoStacksPlainSocketImpl is 87 * loaded, to cache fieldIds for efficiency. This is called everytime 88 * the Java class is loaded. 89 * 90 * Class: java_net_TwoStacksPlainSocketImpl 91 * Method: initProto 92 93 * Signature: ()V 94 */ 95 JNIEXPORT void JNICALL 96 Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) { 97 98 struct protoent *proto = getprotobyname("TCP"); 99 tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto); 100 101 psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;"); 102 CHECK_NULL(psi_fdID); 103 psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;"); 104 CHECK_NULL(psi_fd1ID); 105 psi_addressID = (*env)->GetFieldID(env, cls, "address", 106 "Ljava/net/InetAddress;"); 107 CHECK_NULL(psi_addressID); 108 psi_portID = (*env)->GetFieldID(env, cls, "port", "I"); 109 CHECK_NULL(psi_portID); 110 psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I"); 111 CHECK_NULL(psi_portID); 112 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I"); 113 CHECK_NULL(psi_localportID); 114 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); 115 CHECK_NULL(psi_timeoutID); 116 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); 117 CHECK_NULL(psi_trafficClassID); 118 psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket", 119 "Ljava/net/ServerSocket;"); 120 CHECK_NULL(psi_serverSocketID); 121 IO_fd_fdID = NET_GetFileDescriptorID(env); 122 CHECK_NULL(IO_fd_fdID); 123 } 124 125 /* 126 * Class: java_net_TwoStacksPlainSocketImpl 127 * Method: socketCreate 128 * Signature: (Z)V 129 */ 130 JNIEXPORT void JNICALL 131 Java_java_net_TwoStacksPlainSocketImpl_socketCreate(JNIEnv *env, jobject this, 132 jboolean stream) { 133 jobject fdObj, fd1Obj; 134 int fd, fd1; 135 136 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 137 138 if (IS_NULL(fdObj)) { 139 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 140 "null fd object"); 141 return; 142 } 143 fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); 144 if (fd == -1) { 145 NET_ThrowCurrent(env, "create"); 146 return; 147 } else { 148 /* Set socket attribute so it is not passed to any child process */ 149 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 150 (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd); 151 } 152 if (ipv6_available()) { 153 fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 154 155 if (IS_NULL(fd1Obj)) { 156 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 157 "null fd1 object"); 158 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 159 NET_SocketClose(fd); 160 return; 161 } 162 fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); 163 if (fd1 == -1) { 164 NET_ThrowCurrent(env, "create"); 165 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 166 NET_SocketClose(fd); 167 return; 168 } else { 169 /* Set socket attribute so it is not passed to any child process */ 170 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE); 171 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1); 172 } 173 } else { 174 (*env)->SetObjectField(env, this, psi_fd1ID, NULL); 175 } 176 } 177 178 /* 179 * inetAddress is the address object passed to the socket connect 180 * call. 181 * 182 * Class: java_net_TwoStacksPlainSocketImpl 183 * Method: socketConnect 184 * Signature: (Ljava/net/InetAddress;I)V 185 */ 186 JNIEXPORT void JNICALL 187 Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this, 188 jobject iaObj, jint port, 189 jint timeout) 190 { 191 jint localport = (*env)->GetIntField(env, this, psi_localportID); 192 193 /* family and localport are int fields of iaObj */ 194 int family; 195 jint fd, fd1=-1; 196 jint len; 197 int ipv6_supported = ipv6_available(); 198 199 /* fd initially points to the IPv4 socket and fd1 to the IPv6 socket 200 * If we want to connect to IPv6 then we swap the two sockets/objects 201 * This way, fd is always the connected socket, and fd1 always gets closed. 202 */ 203 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 204 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 205 206 SOCKETADDRESS him; 207 208 /* The result of the connection */ 209 int connect_res; 210 memset((char *)&him, 0, sizeof(him)); 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 = 0; 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, "NET_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 timeout = (*env)->GetIntField(env, this, psi_timeoutID); 583 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 584 jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); 585 586 /* the FileDescriptor field on socket */ 587 jobject socketFdObj; 588 589 /* cache the Inet4/6Address classes */ 590 static jclass inet4Cls; 591 static jclass inet6Cls; 592 593 /* the InetAddress field on socket */ 594 jobject socketAddressObj; 595 596 /* the fd int field on fdObj */ 597 jint fd=-1, fd1=-1; 598 599 SOCKETADDRESS him; 600 jint len; 601 602 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 603 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 604 "Socket closed"); 605 return; 606 } 607 if (!IS_NULL(fdObj)) { 608 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 609 } 610 if (!IS_NULL(fd1Obj)) { 611 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 612 } 613 if (IS_NULL(socket)) { 614 JNU_ThrowNullPointerException(env, "socket is null"); 615 return; 616 } else { 617 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 618 socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID); 619 } 620 if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) { 621 JNU_ThrowNullPointerException(env, "socket address or fd obj"); 622 return; 623 } 624 if (fd != -1 && fd1 != -1) { 625 fd_set rfds; 626 struct timeval t, *tP=&t; 627 int lastfd, res, fd2; 628 FD_ZERO(&rfds); 629 FD_SET(fd,&rfds); 630 FD_SET(fd1,&rfds); 631 if (timeout) { 632 t.tv_sec = timeout/1000; 633 t.tv_usec = (timeout%1000)*1000; 634 } else { 635 tP = NULL; 636 } 637 res = select (fd, &rfds, NULL, NULL, tP); 638 if (res == 0) { 639 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 640 "Accept timed out"); 641 return; 642 } else if (res == 1) { 643 fd2 = FD_ISSET(fd, &rfds)? fd: fd1; 644 } else if (res == 2) { 645 /* avoid starvation */ 646 lastfd = (*env)->GetIntField(env, this, psi_lastfdID); 647 if (lastfd != -1) { 648 fd2 = lastfd==fd? fd1: fd; 649 } else { 650 fd2 = fd; 651 } 652 (*env)->SetIntField(env, this, psi_lastfdID, fd2); 653 } else { 654 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 655 "select failed"); 656 return; 657 } 658 if (fd2 == fd) { /* v4 */ 659 len = sizeof (struct sockaddr_in); 660 } else { 661 len = sizeof (struct SOCKADDR_IN6); 662 } 663 fd = fd2; 664 } else { 665 int ret; 666 if (fd1 != -1) { 667 fd = fd1; 668 len = sizeof (struct SOCKADDR_IN6); 669 } else { 670 len = sizeof (struct sockaddr_in); 671 } 672 if (timeout) { 673 ret = NET_Timeout(fd, timeout); 674 if (ret == 0) { 675 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 676 "Accept timed out"); 677 return; 678 } else if (ret == -1) { 679 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 680 /* REMIND: SOCKET CLOSED PROBLEM */ 681 /* NET_ThrowCurrent(env, "Accept failed"); */ 682 return; 683 } else if (ret == -2) { 684 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 685 "operation interrupted"); 686 return; 687 } 688 } 689 } 690 fd = accept(fd, (struct sockaddr *)&him, &len); 691 if (fd < 0) { 692 /* REMIND: SOCKET CLOSED PROBLEM */ 693 if (fd == -2) { 694 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 695 "operation interrupted"); 696 } else { 697 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 698 "socket closed"); 699 } 700 return; 701 } 702 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0); 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, (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 842 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value) 843 { 844 int fd, fd1; 845 int level = 0, optname = 0, optlen = 0; 846 union { 847 int i; 848 struct linger ling; 849 } optval; 850 851 memset((char *)&optval, 0, sizeof(optval)); 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 and option name. 926 */ 927 if (NET_MapSocketOption(cmd, &level, &optname)) { 928 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 929 return; 930 } 931 932 switch (cmd) { 933 934 case java_net_SocketOptions_TCP_NODELAY : 935 case java_net_SocketOptions_SO_OOBINLINE : 936 case java_net_SocketOptions_SO_KEEPALIVE : 937 case java_net_SocketOptions_SO_REUSEADDR : 938 optval.i = (on ? 1 : 0); 939 optlen = sizeof(optval.i); 940 break; 941 942 case java_net_SocketOptions_SO_SNDBUF : 943 case java_net_SocketOptions_SO_RCVBUF : 944 case java_net_SocketOptions_IP_TOS : 945 { 946 jclass cls; 947 jfieldID fid; 948 949 cls = (*env)->FindClass(env, "java/lang/Integer"); 950 CHECK_NULL(cls); 951 fid = (*env)->GetFieldID(env, cls, "value", "I"); 952 CHECK_NULL(fid); 953 954 optval.i = (*env)->GetIntField(env, value, fid); 955 optlen = sizeof(optval.i); 956 } 957 break; 958 959 case java_net_SocketOptions_SO_LINGER : 960 { 961 jclass cls; 962 jfieldID fid; 963 964 cls = (*env)->FindClass(env, "java/lang/Integer"); 965 CHECK_NULL(cls); 966 fid = (*env)->GetFieldID(env, cls, "value", "I"); 967 CHECK_NULL(fid); 968 969 if (on) { 970 optval.ling.l_onoff = 1; 971 optval.ling.l_linger = 972 (unsigned short)(*env)->GetIntField(env, value, fid); 973 } else { 974 optval.ling.l_onoff = 0; 975 optval.ling.l_linger = 0; 976 } 977 optlen = sizeof(optval.ling); 978 } 979 break; 980 981 default: /* shouldn't get here */ 982 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 983 "Option not supported by TwoStacksPlainSocketImpl"); 984 return; 985 } 986 987 if (fd != -1) { 988 if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) { 989 NET_ThrowCurrent(env, "setsockopt"); 990 } 991 } 992 993 if (fd1 != -1) { 994 if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) { 995 NET_ThrowCurrent(env, "setsockopt"); 996 } 997 } 998 } 999 1000 1001 /* 1002 * Class: java_net_TwoStacksPlainSocketImpl 1003 * Method: socketGetOption 1004 * Signature: (I)I 1005 */ 1006 JNIEXPORT jint JNICALL 1007 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption 1008 (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj) 1009 { 1010 int fd, fd1; 1011 int level = 0, optname = 0, optlen = 0; 1012 union { 1013 int i; 1014 struct linger ling; 1015 } optval; 1016 1017 /* 1018 * Get SOCKET and check it hasn't been closed 1019 */ 1020 fd = getFD(env, this); 1021 fd1 = getFD1(env, this); 1022 memset((char *)&optval, 0, sizeof(optval)); 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 memset((char *)&him, 0, len); 1047 1048 if (fd == -1) { 1049 /* must be an IPV6 only socket. Case where both sockets are != -1 1050 * is handled in java 1051 */ 1052 fd = getFD1 (env, this); 1053 } 1054 1055 if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) { 1056 JNU_ThrowByNameWithMessageAndLastError 1057 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 1058 return -1; 1059 } 1060 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 1061 CHECK_NULL_RETURN(iaObj, -1); 1062 1063 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 1064 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 1065 CHECK_NULL_RETURN(iaFieldID, -1); 1066 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 1067 return 0; /* notice change from before */ 1068 } 1069 1070 /* 1071 * Map the Java level socket option to the platform specific 1072 * level and option name. 1073 */ 1074 if (NET_MapSocketOption(opt, &level, &optname)) { 1075 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 1076 return -1; 1077 } 1078 1079 /* 1080 * Args are int except for SO_LINGER 1081 */ 1082 if (opt == java_net_SocketOptions_SO_LINGER) { 1083 optlen = sizeof(optval.ling); 1084 } else { 1085 optlen = sizeof(optval.i); 1086 optval.i = 0; 1087 } 1088 1089 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 1090 NET_ThrowCurrent(env, "getsockopt"); 1091 return -1; 1092 } 1093 1094 switch (opt) { 1095 case java_net_SocketOptions_SO_LINGER: 1096 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 1097 1098 case java_net_SocketOptions_SO_SNDBUF: 1099 case java_net_SocketOptions_SO_RCVBUF: 1100 case java_net_SocketOptions_IP_TOS: 1101 return optval.i; 1102 1103 case java_net_SocketOptions_TCP_NODELAY : 1104 case java_net_SocketOptions_SO_OOBINLINE : 1105 case java_net_SocketOptions_SO_KEEPALIVE : 1106 case java_net_SocketOptions_SO_REUSEADDR : 1107 return (optval.i == 0) ? -1 : 1; 1108 1109 default: /* shouldn't get here */ 1110 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1111 "Option not supported by TwoStacksPlainSocketImpl"); 1112 return -1; 1113 } 1114 } 1115 1116 /* 1117 * Class: java_net_TwoStacksPlainSocketImpl 1118 * Method: socketShutdown 1119 * Signature: (I)V 1120 */ 1121 JNIEXPORT void JNICALL 1122 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 1123 jint howto) 1124 { 1125 1126 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1127 jint fd; 1128 1129 /* 1130 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 1131 * -1 already? 1132 */ 1133 if (IS_NULL(fdObj)) { 1134 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1135 "socket already closed"); 1136 return; 1137 } else { 1138 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1139 } 1140 shutdown(fd, howto); 1141 } 1142 1143 /* 1144 * Class: java_net_TwoStacksPlainSocketImpl 1145 * Method: socketSendUrgentData 1146 * Signature: (B)V 1147 */ 1148 JNIEXPORT void JNICALL 1149 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 1150 jint data) { 1151 /* The fd field */ 1152 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1153 int n, fd; 1154 unsigned char d = data & 0xff; 1155 1156 if (IS_NULL(fdObj)) { 1157 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1158 return; 1159 } else { 1160 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1161 /* Bug 4086704 - If the Socket associated with this file descriptor 1162 * was closed (sysCloseFD), the file descriptor is set to -1. 1163 */ 1164 if (fd == -1) { 1165 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1166 return; 1167 } 1168 1169 } 1170 n = send(fd, (char *)&data, 1, MSG_OOB); 1171 if (n == -1) { 1172 NET_ThrowCurrent(env, "send"); 1173 return; 1174 } 1175 }