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