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