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 "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(JNIEnv *env, 842 jobject this, 843 jint cmd, jboolean on, 844 jobject value) { 845 int fd, fd1; 846 int level = 0, optname = 0, optlen = 0; 847 union { 848 int i; 849 struct linger ling; 850 } optval; 851 852 memset((char *)&optval, 0, sizeof(optval)); 853 /* 854 * Get SOCKET and check that it hasn't been closed 855 */ 856 fd = getFD(env, this); 857 fd1 = getFD1(env, this); 858 if (fd < 0 && fd1 < 0) { 859 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 860 return; 861 } 862 863 /* 864 * SO_TIMEOUT is the socket option used to specify the timeout 865 * for ServerSocket.accept and Socket.getInputStream().read. 866 * It does not typically map to a native level socket option. 867 * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO 868 * socket option to specify a receive timeout on the socket. This 869 * receive timeout is applicable to Socket only and the socket 870 * option should not be set on ServerSocket. 871 */ 872 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 873 874 /* 875 * Don't enable the socket option on ServerSocket as it's 876 * meaningless (we don't receive on a ServerSocket). 877 */ 878 jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID); 879 if (ssObj != NULL) { 880 return; 881 } 882 883 /* 884 * SO_RCVTIMEO is only supported on Microsoft's implementation 885 * of Windows Sockets so if WSAENOPROTOOPT returned then 886 * reset flag and timeout will be implemented using 887 * select() -- see SocketInputStream.socketRead. 888 */ 889 if (isRcvTimeoutSupported) { 890 jclass iCls = (*env)->FindClass(env, "java/lang/Integer"); 891 jfieldID i_valueID; 892 jint timeout; 893 894 CHECK_NULL(iCls); 895 i_valueID = (*env)->GetFieldID(env, iCls, "value", "I"); 896 CHECK_NULL(i_valueID); 897 timeout = (*env)->GetIntField(env, value, i_valueID); 898 899 /* 900 * Disable SO_RCVTIMEO if timeout is <= 5 second. 901 */ 902 if (timeout <= 5000) { 903 timeout = 0; 904 } 905 906 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 907 sizeof(timeout)) < 0) { 908 if (WSAGetLastError() == WSAENOPROTOOPT) { 909 isRcvTimeoutSupported = JNI_FALSE; 910 } else { 911 NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); 912 } 913 } 914 if (fd1 != -1) { 915 if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 916 sizeof(timeout)) < 0) { 917 NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO"); 918 } 919 } 920 } 921 return; 922 } 923 924 /* 925 * Map the Java level socket option to the platform specific 926 * level 927 */ 928 if (NET_MapSocketOption(cmd, &level, &optname)) { 929 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 930 "Invalid option"); 931 return; 932 } 933 934 switch (cmd) { 935 936 case java_net_SocketOptions_TCP_NODELAY : 937 case java_net_SocketOptions_SO_OOBINLINE : 938 case java_net_SocketOptions_SO_KEEPALIVE : 939 case java_net_SocketOptions_SO_REUSEADDR : 940 optval.i = (on ? 1 : 0); 941 optlen = sizeof(optval.i); 942 break; 943 944 case java_net_SocketOptions_SO_SNDBUF : 945 case java_net_SocketOptions_SO_RCVBUF : 946 case java_net_SocketOptions_IP_TOS : 947 { 948 jclass cls; 949 jfieldID fid; 950 951 cls = (*env)->FindClass(env, "java/lang/Integer"); 952 CHECK_NULL(cls); 953 fid = (*env)->GetFieldID(env, cls, "value", "I"); 954 CHECK_NULL(fid); 955 956 optval.i = (*env)->GetIntField(env, value, fid); 957 optlen = sizeof(optval.i); 958 } 959 break; 960 961 case java_net_SocketOptions_SO_LINGER : 962 { 963 jclass cls; 964 jfieldID fid; 965 966 cls = (*env)->FindClass(env, "java/lang/Integer"); 967 CHECK_NULL(cls); 968 fid = (*env)->GetFieldID(env, cls, "value", "I"); 969 CHECK_NULL(fid); 970 971 if (on) { 972 optval.ling.l_onoff = 1; 973 optval.ling.l_linger = 974 (unsigned short)(*env)->GetIntField(env, value, fid); 975 } else { 976 optval.ling.l_onoff = 0; 977 optval.ling.l_linger = 0; 978 } 979 optlen = sizeof(optval.ling); 980 } 981 break; 982 983 default: /* shouldn't get here */ 984 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 985 "Option not supported by TwoStacksPlainSocketImpl"); 986 return; 987 } 988 989 if (fd != -1) { 990 if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) { 991 NET_ThrowCurrent(env, "setsockopt"); 992 } 993 } 994 995 if (fd1 != -1) { 996 if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) { 997 NET_ThrowCurrent(env, "setsockopt"); 998 } 999 } 1000 } 1001 1002 1003 /* 1004 * Class: java_net_TwoStacksPlainSocketImpl 1005 * Method: socketGetOption 1006 * Signature: (I)I 1007 */ 1008 JNIEXPORT jint JNICALL 1009 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this, 1010 jint opt, jobject iaContainerObj) { 1011 1012 int fd, fd1; 1013 int level = 0, optname = 0, optlen = 0; 1014 union { 1015 int i; 1016 struct linger ling; 1017 } optval; 1018 /* 1019 * Get SOCKET and check it hasn't been closed 1020 */ 1021 fd = getFD(env, this); 1022 fd1 = getFD1(env, this); 1023 memset((char *)&optval, 0, sizeof(optval)); 1024 1025 if (fd < 0 && fd1 < 0) { 1026 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 1027 return -1; 1028 } 1029 if (fd < 0) { 1030 fd = fd1; 1031 } 1032 1033 /* For IPv6, we assume both sockets have the same setting always */ 1034 1035 /* 1036 * SO_BINDADDR isn't a socket option 1037 */ 1038 if (opt == java_net_SocketOptions_SO_BINDADDR) { 1039 SOCKETADDRESS him; 1040 int len; 1041 int port; 1042 jobject iaObj; 1043 jclass iaCntrClass; 1044 jfieldID iaFieldID; 1045 1046 len = sizeof(him); 1047 memset((char *)&him, 0, len); 1048 1049 if (fd == -1) { 1050 /* must be an IPV6 only socket. Case where both sockets are != -1 1051 * is handled in java 1052 */ 1053 fd = getFD1 (env, this); 1054 } 1055 1056 if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) { 1057 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1058 "Error getting socket name"); 1059 return -1; 1060 } 1061 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 1062 CHECK_NULL_RETURN(iaObj, -1); 1063 1064 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 1065 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 1066 CHECK_NULL_RETURN(iaFieldID, -1); 1067 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 1068 return 0; /* notice change from before */ 1069 } 1070 1071 /* 1072 * Map the Java level socket option to the platform specific 1073 * level and option name. 1074 */ 1075 if (NET_MapSocketOption(opt, &level, &optname)) { 1076 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1077 return -1; 1078 } 1079 1080 /* 1081 * Args are int except for SO_LINGER 1082 */ 1083 if (opt == java_net_SocketOptions_SO_LINGER) { 1084 optlen = sizeof(optval.ling); 1085 } else { 1086 optlen = sizeof(optval.i); 1087 optval.i = 0; 1088 } 1089 1090 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 1091 NET_ThrowCurrent(env, "getsockopt"); 1092 return -1; 1093 } 1094 1095 switch (opt) { 1096 case java_net_SocketOptions_SO_LINGER: 1097 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 1098 1099 case java_net_SocketOptions_SO_SNDBUF: 1100 case java_net_SocketOptions_SO_RCVBUF: 1101 case java_net_SocketOptions_IP_TOS: 1102 return optval.i; 1103 1104 case java_net_SocketOptions_TCP_NODELAY : 1105 case java_net_SocketOptions_SO_OOBINLINE : 1106 case java_net_SocketOptions_SO_KEEPALIVE : 1107 case java_net_SocketOptions_SO_REUSEADDR : 1108 return (optval.i == 0) ? -1 : 1; 1109 1110 default: /* shouldn't get here */ 1111 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1112 "Option not supported by TwoStacksPlainSocketImpl"); 1113 return -1; 1114 } 1115 } 1116 1117 /* 1118 * Class: java_net_TwoStacksPlainSocketImpl 1119 * Method: socketShutdown 1120 * Signature: (I)V 1121 */ 1122 JNIEXPORT void JNICALL 1123 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 1124 jint howto) 1125 { 1126 1127 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1128 jint fd; 1129 1130 /* 1131 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being 1132 * -1 already? 1133 */ 1134 if (IS_NULL(fdObj)) { 1135 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1136 "socket already closed"); 1137 return; 1138 } else { 1139 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1140 } 1141 shutdown(fd, howto); 1142 } 1143 1144 /* 1145 * Class: java_net_TwoStacksPlainSocketImpl 1146 * Method: socketSendUrgentData 1147 * Signature: (B)V 1148 */ 1149 JNIEXPORT void JNICALL 1150 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 1151 jint data) { 1152 /* The fd field */ 1153 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 1154 int n, fd; 1155 unsigned char d = data & 0xff; 1156 1157 if (IS_NULL(fdObj)) { 1158 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1159 return; 1160 } else { 1161 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1162 /* Bug 4086704 - If the Socket associated with this file descriptor 1163 * was closed (sysCloseFD), the file descriptor is set to -1. 1164 */ 1165 if (fd == -1) { 1166 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 1167 return; 1168 } 1169 1170 } 1171 n = send(fd, (char *)&data, 1, MSG_OOB); 1172 if (n == -1) { 1173 NET_ThrowCurrent(env, "send"); 1174 return; 1175 } 1176 }