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