1 /* 2 * Copyright (c) 2007, 2018, 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 #include "net_util.h" 26 27 #include "java_net_DualStackPlainSocketImpl.h" 28 #include "java_net_SocketOptions.h" 29 30 /************************************************************************ 31 * DualStackPlainSocketImpl 32 */ 33 34 static jfieldID IO_fd_fdID; 35 36 jfieldID psi_fdID; 37 jfieldID psi_addressID; 38 jfieldID psi_portID; 39 jfieldID psi_localportID; 40 jfieldID psi_timeoutID; 41 42 43 static jboolean configureBlocking(JNIEnv *env, jint fd, jboolean blocking) { 44 u_long arg = (blocking == JNI_TRUE) ? 0 : 1; 45 46 if (ioctlsocket(fd, FIONBIO, &arg) == SOCKET_ERROR) { 47 if (!(*env)->ExceptionCheck(env)) { 48 NET_ThrowNew(env, WSAGetLastError(), "configureBlocking"); 49 } 50 return JNI_FALSE; 51 } 52 53 return JNI_TRUE; 54 } 55 56 /* 57 * Class: java_net_DualStackPlainSocketImpl 58 * Method: initProto 59 * Signature: ()V 60 */ 61 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initProto 62 (JNIEnv *env, jclass cls) { 63 64 psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;"); 65 CHECK_NULL(psi_fdID); 66 psi_addressID = (*env)->GetFieldID(env, cls, "address", 67 "Ljava/net/InetAddress;"); 68 CHECK_NULL(psi_addressID); 69 psi_portID = (*env)->GetFieldID(env, cls, "port", "I"); 70 CHECK_NULL(psi_portID); 71 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I"); 72 CHECK_NULL(psi_localportID); 73 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); 74 CHECK_NULL(psi_timeoutID); 75 76 initInetAddressIDs(env); 77 78 // implement read timeout with select. 79 isRcvTimeoutSupported = 0; 80 81 IO_fd_fdID = NET_GetFileDescriptorID(env); 82 CHECK_NULL(IO_fd_fdID); 83 } 84 85 /* 86 * Class: java_net_DualStackPlainSocketImpl 87 * Method: socketCreate 88 * Signature: (Z)V 89 */ 90 JNIEXPORT void JNICALL 91 Java_java_net_DualStackPlainSocketImpl_socketCreate(JNIEnv *env, jobject this, 92 jboolean stream) { 93 jobject fdObj; 94 int fd; 95 96 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 97 98 if (IS_NULL(fdObj)) { 99 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 100 "null fd object"); 101 return; 102 } 103 fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); 104 if (fd == INVALID_SOCKET) { 105 NET_ThrowNew(env, WSAGetLastError(), "create"); 106 return; 107 } else { 108 int arg = 0; 109 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 110 sizeof(int)) == SOCKET_ERROR) { 111 NET_ThrowNew(env, WSAGetLastError(), "create"); 112 } 113 114 /* Set socket attribute so it is not passed to any child process */ 115 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 116 (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd); 117 } 118 } 119 120 /* 121 * Class: java_net_DualStackPlainSocketImpl 122 * Method: socketBind 123 * Signature: (Ljava/net/InetAddress;I)V 124 */ 125 JNIEXPORT void JNICALL 126 Java_java_net_DualStackPlainSocketImpl_socketBind(JNIEnv *env, jobject this, 127 jobject iaObj, jint localport, 128 jboolean exclBind) { 129 130 /* fdObj is the FileDescriptor field on this */ 131 jobject fdObj; 132 /* fd is an int field on fdObj */ 133 int fd, len = 0; 134 135 int rv; 136 137 SOCKETADDRESS sa; 138 139 fdObj = (*env)->GetObjectField(env, this, psi_fdID); 140 141 if (IS_NULL(fdObj)) { 142 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 143 "Socket closed"); 144 return; 145 } else { 146 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 147 } 148 if (IS_NULL(iaObj)) { 149 JNU_ThrowNullPointerException(env, "inet address argument"); 150 return; 151 } 152 153 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len, 154 JNI_TRUE) != 0) { 155 return; 156 } 157 rv = NET_WinBind(fd, &sa, len, exclBind); 158 159 if (rv == SOCKET_ERROR) { 160 NET_ThrowNew(env, WSAGetLastError(), "NET_Bind"); 161 return; 162 } 163 164 /* set the address */ 165 (*env)->SetObjectField(env, this, psi_addressID, iaObj); 166 167 /* intialize the local port */ 168 if (localport == 0) { 169 /* Now that we're a bound socket, let's extract the port number 170 * that the system chose for us and store it in the Socket object. 171 */ 172 int len = sizeof(SOCKETADDRESS); 173 u_short port; 174 175 if (getsockname(fd, &sa.sa, &len) == -1) { 176 NET_ThrowCurrent(env, "getsockname in plain socketBind"); 177 return; 178 } 179 port = ntohs((u_short) GET_PORT (&sa)); 180 181 (*env)->SetIntField(env, this, psi_localportID, (int)port); 182 } else { 183 (*env)->SetIntField(env, this, psi_localportID, localport); 184 } 185 } 186 187 /* 188 * Class: java_net_DualStackPlainSocketImpl 189 * Method: socketConnect 190 * Signature: (Ljava/net/InetAddress;I)V 191 */ 192 JNIEXPORT void JNICALL 193 Java_java_net_DualStackPlainSocketImpl_socketConnect(JNIEnv *env, jobject this, 194 jobject iaObj, jint port, 195 jint timeout) 196 { 197 jint localport = (*env)->GetIntField(env, this, psi_localportID); 198 199 /* family and localport are int fields of iaObj */ 200 jint fd = -1; 201 jint len; 202 203 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 204 205 SOCKETADDRESS sa; 206 207 /* The result of the connection */ 208 int connect_res; 209 memset((char *)&sa, 0, sizeof(sa)); 210 211 if (IS_NULL(fdObj)) { 212 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 213 "socket closed"); 214 return; 215 } 216 217 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 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, &sa, &len, 225 JNI_TRUE) != 0) { 226 return; 227 } 228 229 if (fd == -1) { 230 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 231 "Destination unreachable"); 232 return; 233 } 234 235 if (timeout <= 0) { 236 connect_res = connect(fd, &sa.sa, len); 237 if (connect_res == SOCKET_ERROR) { 238 int err = WSAGetLastError(); 239 if (err == WSAEADDRNOTAVAIL) { 240 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 241 "connect: Address is invalid on local machine, or port is not valid on remote machine"); 242 } else { 243 NET_ThrowNew(env, err, "connect"); 244 } 245 return; 246 } 247 } else { 248 if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) { 249 // exception pending 250 return; 251 } 252 253 /* initiate the connect */ 254 connect_res = connect(fd, &sa.sa, len); 255 if (connect_res == SOCKET_ERROR) { 256 int err = WSAGetLastError(); 257 if (err != WSAEWOULDBLOCK) { 258 connect_res = err; 259 } else { 260 fd_set wr, ex; 261 struct timeval t; 262 263 FD_ZERO(&wr); 264 FD_ZERO(&ex); 265 FD_SET(fd, &wr); 266 FD_SET(fd, &ex); 267 t.tv_sec = timeout / 1000; 268 t.tv_usec = (timeout % 1000) * 1000; 269 270 /* 271 * Wait for timout, connection established or 272 * connection failed. 273 */ 274 connect_res = select(fd+1, 0, &wr, &ex, &t); 275 276 /* 277 * Timeout before connection is established/failed so 278 * we throw exception and shutdown input/output to prevent 279 * socket from being used. 280 * The socket should be closed immediately by the caller. 281 */ 282 if (connect_res == 0) { 283 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 284 "connect timed out"); 285 shutdown( fd, SD_BOTH ); 286 287 /* make socket blocking again - just in case */ 288 configureBlocking(env, fd, JNI_TRUE); 289 return; 290 } 291 /* 292 * Socket is writable or error occurred. On some Windows editions 293 * the socket will appear writable when the connect fails so we 294 * check for error rather than writable. 295 */ 296 if (!FD_ISSET(fd, &ex)) { 297 connect_res = 0; /* connection established */ 298 } else { 299 int optlen = sizeof(&connect_res); 300 301 /* 302 * Connection failed. The logic here is designed to work around 303 * bug on Windows NT whereby using getsockopt to obtain the 304 * last error (SO_ERROR) indicates there is no error. The workaround 305 * on NT is to allow winsock to be scheduled and this is done by 306 * yielding and retrying. As yielding is problematic in heavy 307 * load conditions we attempt up to 3 times to get the error reason. 308 */ 309 int retry; 310 for (retry=0; retry<3; retry++) { 311 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, 312 (char*)&connect_res, &optlen); 313 if (connect_res) { 314 break; 315 } 316 Sleep(0); 317 } 318 319 if (connect_res == 0) { 320 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 321 "Unable to establish connection"); 322 } else { 323 NET_ThrowNew(env, connect_res, "connect"); 324 } 325 return; 326 } 327 } 328 } 329 330 if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) { 331 // exception pending 332 return; 333 } 334 } 335 336 if (connect_res) { 337 if (connect_res == WSAEADDRNOTAVAIL) { 338 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", 339 "connect: Address is invalid on local machine, or port is not valid on remote machine"); 340 } else { 341 NET_ThrowNew(env, connect_res, "connect"); 342 } 343 return; 344 } 345 346 /* 347 * we need to initialize the local port field if bind was called 348 * previously to the connect (by the client) then localport field 349 * will already be initialized 350 */ 351 if (localport == 0) { 352 /* Now that we're a connected socket, let's extract the port number 353 * that the system chose for us and store it in the Socket object. 354 */ 355 len = sizeof(sa); 356 memset((char *)&sa, 0, len); 357 358 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { 359 if (WSAGetLastError() == WSAENOTSOCK) { 360 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 361 "Socket closed"); 362 } else { 363 NET_ThrowNew(env, WSAGetLastError(), "getsockname failed"); 364 } 365 return; 366 } 367 localport = (jint) ntohs((u_short)GET_PORT(&sa)); 368 (*env)->SetIntField(env, this, psi_localportID, (int) localport); 369 } 370 } 371 372 /* 373 * Class: java_net_DualStackPlainSocketImpl 374 * Method: localAddress 375 * Signature: (ILjava/net/InetAddressContainer;)V 376 */ 377 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress 378 (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) { 379 int port; 380 SOCKETADDRESS sa; 381 int len = sizeof(sa); 382 jobject iaObj; 383 jclass iaContainerClass; 384 jfieldID iaFieldID; 385 386 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { 387 NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); 388 return; 389 } 390 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 391 CHECK_NULL(iaObj); 392 393 iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj); 394 iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;"); 395 CHECK_NULL(iaFieldID); 396 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 397 } 398 399 /* 400 * Class: java_net_DualStackPlainSocketImpl 401 * Method: socketListen 402 * Signature: (I)V 403 */ 404 JNIEXPORT void JNICALL 405 Java_java_net_DualStackPlainSocketImpl_socketListen 406 (JNIEnv *env, jobject this, jint count) 407 { 408 /* this FileDescriptor fd field */ 409 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 410 /* fdObj's int fd field */ 411 int fd = INVALID_SOCKET; 412 413 if (IS_NULL(fdObj)) { 414 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 415 "socket closed"); 416 return; 417 } 418 419 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 420 421 if (listen(fd, count) == SOCKET_ERROR) { 422 NET_ThrowNew(env, WSAGetLastError(), "listen failed"); 423 } 424 } 425 426 /* 427 * Class: java_net_DualStackPlainSocketImpl 428 * Method: socketAccept 429 * Signature: (Ljava/net/SocketImpl;)V 430 */ 431 JNIEXPORT void JNICALL 432 Java_java_net_DualStackPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 433 jobject socket) 434 { 435 /* fields on this */ 436 jint port=0; 437 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID); 438 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 439 440 /* the FileDescriptor field on socket */ 441 jobject socketFdObj; 442 443 /* the InetAddress field on socket */ 444 jobject socketAddressObj; 445 446 /* the fd int field on fdObj */ 447 jint fd=-1; 448 449 /* accepted fd */ 450 jint newfd; 451 452 SOCKETADDRESS sa; 453 jint len; 454 int ret; 455 456 if (IS_NULL(fdObj)) { 457 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 458 "Socket closed"); 459 return; 460 } 461 462 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 463 464 if (IS_NULL(socket)) { 465 JNU_ThrowNullPointerException(env, "socket is null"); 466 return; 467 } else { 468 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 469 } 470 if (IS_NULL(socketFdObj)) { 471 JNU_ThrowNullPointerException(env, "socket fd obj"); 472 return; 473 } 474 475 if (timeout > 0) { 476 if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) { 477 // exception pending 478 return; 479 } 480 481 ret = NET_Timeout(fd, timeout); 482 if (ret == 0) { 483 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 484 "Accept timed out"); 485 configureBlocking(env, fd, JNI_TRUE); 486 return; 487 } else if (ret == -1) { 488 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 489 configureBlocking(env, fd, JNI_TRUE); 490 return; 491 } else if (ret == -2) { 492 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 493 "operation interrupted"); 494 configureBlocking(env, fd, JNI_TRUE); 495 return; 496 } 497 } 498 499 len = sizeof(sa); 500 memset((char *)&sa, 0, len); 501 newfd = accept(fd, &sa.sa, &len); 502 503 if (timeout > 0) { 504 if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) { 505 if (newfd != INVALID_SOCKET) { 506 closesocket(newfd); 507 } 508 // exception pending 509 return; 510 } 511 } 512 513 if (newfd == INVALID_SOCKET) { 514 if (WSAGetLastError() == -2) { 515 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 516 "operation interrupted"); 517 } else { 518 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 519 "socket closed"); 520 } 521 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, -1); 522 return; 523 } 524 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); 525 if (configureBlocking(env, newfd, JNI_TRUE) == JNI_FALSE) { 526 closesocket(newfd); 527 // exception pending 528 return; 529 } 530 531 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 532 if (socketAddressObj == NULL) { 533 /* should be pending exception */ 534 closesocket(newfd); 535 return; 536 } 537 538 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 539 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 540 (*env)->SetIntField(env, socket, psi_portID, (int)port); 541 /* also fill up the local port information */ 542 port = (*env)->GetIntField(env, this, psi_localportID); 543 (*env)->SetIntField(env, socket, psi_localportID, port); 544 } 545 546 /* 547 * Class: java_net_DualStackPlainSocketImpl 548 * Method: socketAvailable 549 * Signature: ()I 550 */ 551 JNIEXPORT jint JNICALL 552 Java_java_net_DualStackPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) { 553 554 jint available = -1; 555 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 556 jint fd; 557 558 if (IS_NULL(fdObj)) { 559 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 560 return -1; 561 } else { 562 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 563 } 564 565 if (ioctlsocket(fd, FIONREAD, &available) == SOCKET_ERROR) { 566 NET_ThrowNew(env, WSAGetLastError(), "socket available"); 567 } 568 return available; 569 } 570 571 /* 572 * Class: java_net_DualStackPlainSocketImpl 573 * Method: socketClose 574 * Signature: ()V 575 */ 576 JNIEXPORT void JNICALL 577 Java_java_net_DualStackPlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 578 jboolean useDeferredClose) { 579 580 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 581 jint fd=-1; 582 583 if (IS_NULL(fdObj)) { 584 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 585 "socket already closed"); 586 return; 587 } 588 if (!IS_NULL(fdObj)) { 589 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 590 } 591 if (fd != -1) { 592 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 593 NET_SocketClose(fd); 594 } 595 } 596 597 /* 598 * Class: java_net_DualStackPlainSocketImpl 599 * Method: socketShutdown 600 * Signature: (I)V 601 */ 602 JNIEXPORT void JNICALL 603 Java_java_net_DualStackPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 604 jint howto) 605 { 606 607 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 608 jint fd; 609 610 if (IS_NULL(fdObj)) { 611 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 612 "socket already closed"); 613 return; 614 } else { 615 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 616 } 617 shutdown(fd, howto); 618 } 619 620 /* 621 * Class: java_net_DualStackPlainSocketImpl 622 * Method: getIntOption 623 * Signature: (II)I 624 */ 625 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption 626 (JNIEnv *env, jclass clazz, jint fd, jint cmd) 627 { 628 int level = 0, opt = 0; 629 int result=0; 630 struct linger linger = {0, 0}; 631 char *arg; 632 int arglen; 633 634 if (NET_MapSocketOption(cmd, &level, &opt) < 0) { 635 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 636 return -1; 637 } 638 639 if (opt == java_net_SocketOptions_SO_LINGER) { 640 arg = (char *)&linger; 641 arglen = sizeof(linger); 642 } else { 643 arg = (char *)&result; 644 arglen = sizeof(result); 645 } 646 647 if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) { 648 NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); 649 return -1; 650 } 651 652 if (opt == java_net_SocketOptions_SO_LINGER) 653 return linger.l_onoff ? linger.l_linger : -1; 654 else 655 return result; 656 } 657 658 /* 659 * Class: java_net_DualStackPlainSocketImpl 660 * Method: socketNativeSetOption 661 * Signature: (IZLjava/lang/Object;)V 662 */ 663 JNIEXPORT void JNICALL 664 Java_java_net_DualStackPlainSocketImpl_socketNativeSetOption 665 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value) 666 { 667 /* The fd field */ 668 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 669 670 jint fd; 671 int level = 0, optname = 0, optlen = 0; 672 union { 673 int i; 674 struct linger ling; 675 } optval; 676 677 memset((char *)&optval, 0, sizeof(optval)); 678 679 /* 680 * Get SOCKET and check that it hasn't been closed 681 */ 682 if (IS_NULL(fdObj)) { 683 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 684 return; 685 } else { 686 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 687 } 688 if (fd < 0) { 689 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 690 return; 691 } 692 693 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 694 // timeout implemented through select. 695 return; 696 } 697 698 /* 699 * Map the Java level socket option to the platform specific 700 * level and option name. 701 */ 702 if (NET_MapSocketOption(cmd, &level, &optname)) { 703 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 704 return; 705 } 706 707 switch (cmd) { 708 709 case java_net_SocketOptions_TCP_NODELAY : 710 case java_net_SocketOptions_SO_OOBINLINE : 711 case java_net_SocketOptions_SO_KEEPALIVE : 712 case java_net_SocketOptions_SO_REUSEADDR : 713 optval.i = (on ? 1 : 0); 714 optlen = sizeof(optval.i); 715 break; 716 717 case java_net_SocketOptions_SO_SNDBUF : 718 case java_net_SocketOptions_SO_RCVBUF : 719 case java_net_SocketOptions_IP_TOS : 720 { 721 jclass cls; 722 jfieldID fid; 723 724 cls = (*env)->FindClass(env, "java/lang/Integer"); 725 CHECK_NULL(cls); 726 fid = (*env)->GetFieldID(env, cls, "value", "I"); 727 CHECK_NULL(fid); 728 729 optval.i = (*env)->GetIntField(env, value, fid); 730 optlen = sizeof(optval.i); 731 } 732 break; 733 734 case java_net_SocketOptions_SO_LINGER : 735 { 736 jclass cls; 737 jfieldID fid; 738 739 cls = (*env)->FindClass(env, "java/lang/Integer"); 740 CHECK_NULL(cls); 741 fid = (*env)->GetFieldID(env, cls, "value", "I"); 742 CHECK_NULL(fid); 743 744 if (on) { 745 optval.ling.l_onoff = 1; 746 optval.ling.l_linger = 747 (unsigned short)(*env)->GetIntField(env, value, fid); 748 } else { 749 optval.ling.l_onoff = 0; 750 optval.ling.l_linger = 0; 751 } 752 optlen = sizeof(optval.ling); 753 } 754 break; 755 756 default: /* shouldn't get here */ 757 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 758 "Option not supported by DualStackPlainSocketImpl"); 759 return; 760 } 761 762 if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) { 763 NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); 764 } 765 } 766 767 /* 768 * Class: java_net_DualStackPlainSocketImpl 769 * Method: socketNativeGetOption 770 * Signature: (ILjava/lang/Object;)I 771 */ 772 JNIEXPORT jint JNICALL 773 Java_java_net_DualStackPlainSocketImpl_socketNativeGetOption 774 (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj) 775 { 776 return -1; 777 } 778 779 /* 780 * Class: java_net_DualStackPlainSocketImpl 781 * Method: socketSendUrgentData 782 * Signature: (B)V 783 */ 784 JNIEXPORT void JNICALL 785 Java_java_net_DualStackPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 786 jint data) { 787 /* The fd field */ 788 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 789 int n, fd; 790 unsigned char d = (unsigned char) data & 0xff; 791 792 if (IS_NULL(fdObj)) { 793 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 794 return; 795 } else { 796 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 797 798 if (fd == -1) { 799 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 800 return; 801 } 802 803 } 804 n = send(fd, (char *)&data, 1, MSG_OOB); 805 if (n == SOCKET_ERROR) { 806 NET_ThrowNew(env, WSAGetLastError(), "send"); 807 } 808 }