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