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: socketListen 375 * Signature: (I)V 376 */ 377 JNIEXPORT void JNICALL 378 Java_java_net_DualStackPlainSocketImpl_socketListen 379 (JNIEnv *env, jobject this, jint count) 380 { 381 /* this FileDescriptor fd field */ 382 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 383 /* fdObj's int fd field */ 384 int fd = INVALID_SOCKET; 385 386 if (IS_NULL(fdObj)) { 387 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 388 "socket closed"); 389 return; 390 } 391 392 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 393 394 if (listen(fd, count) == SOCKET_ERROR) { 395 NET_ThrowNew(env, WSAGetLastError(), "listen failed"); 396 } 397 } 398 399 /* 400 * Class: java_net_DualStackPlainSocketImpl 401 * Method: socketAccept 402 * Signature: (Ljava/net/SocketImpl;)V 403 */ 404 JNIEXPORT void JNICALL 405 Java_java_net_DualStackPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 406 jobject socket) 407 { 408 /* fields on this */ 409 jint port=0; 410 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID); 411 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 412 413 /* the FileDescriptor field on socket */ 414 jobject socketFdObj; 415 416 /* the InetAddress field on socket */ 417 jobject socketAddressObj; 418 419 /* the fd int field on fdObj */ 420 jint fd=-1; 421 422 /* accepted fd */ 423 jint newfd; 424 425 SOCKETADDRESS sa; 426 jint len; 427 int ret; 428 429 if (IS_NULL(fdObj)) { 430 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 431 "Socket closed"); 432 return; 433 } 434 435 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 436 437 if (IS_NULL(socket)) { 438 JNU_ThrowNullPointerException(env, "socket is null"); 439 return; 440 } else { 441 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 442 } 443 if (IS_NULL(socketFdObj)) { 444 JNU_ThrowNullPointerException(env, "socket fd obj"); 445 return; 446 } 447 448 if (timeout > 0) { 449 if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) { 450 // exception pending 451 return; 452 } 453 454 ret = NET_Timeout(fd, timeout); 455 if (ret == 0) { 456 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 457 "Accept timed out"); 458 configureBlocking(env, fd, JNI_TRUE); 459 return; 460 } else if (ret == -1) { 461 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 462 configureBlocking(env, fd, JNI_TRUE); 463 return; 464 } else if (ret == -2) { 465 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 466 "operation interrupted"); 467 configureBlocking(env, fd, JNI_TRUE); 468 return; 469 } 470 } 471 472 len = sizeof(sa); 473 memset((char *)&sa, 0, len); 474 newfd = accept(fd, &sa.sa, &len); 475 476 if (timeout > 0) { 477 if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) { 478 if (newfd != INVALID_SOCKET) { 479 closesocket(newfd); 480 } 481 // exception pending 482 return; 483 } 484 } 485 486 if (newfd == INVALID_SOCKET) { 487 if (WSAGetLastError() == -2) { 488 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 489 "operation interrupted"); 490 } else { 491 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 492 "socket closed"); 493 } 494 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, -1); 495 return; 496 } 497 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); 498 if (configureBlocking(env, newfd, JNI_TRUE) == JNI_FALSE) { 499 closesocket(newfd); 500 // exception pending 501 return; 502 } 503 504 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 505 if (socketAddressObj == NULL) { 506 /* should be pending exception */ 507 closesocket(newfd); 508 return; 509 } 510 511 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 512 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 513 (*env)->SetIntField(env, socket, psi_portID, (int)port); 514 /* also fill up the local port information */ 515 port = (*env)->GetIntField(env, this, psi_localportID); 516 (*env)->SetIntField(env, socket, psi_localportID, port); 517 } 518 519 /* 520 * Class: java_net_DualStackPlainSocketImpl 521 * Method: socketAvailable 522 * Signature: ()I 523 */ 524 JNIEXPORT jint JNICALL 525 Java_java_net_DualStackPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) { 526 527 jint available = -1; 528 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 529 jint fd; 530 531 if (IS_NULL(fdObj)) { 532 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 533 return -1; 534 } else { 535 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 536 } 537 538 if (ioctlsocket(fd, FIONREAD, &available) == SOCKET_ERROR) { 539 NET_ThrowNew(env, WSAGetLastError(), "socket available"); 540 } 541 return available; 542 } 543 544 /* 545 * Class: java_net_DualStackPlainSocketImpl 546 * Method: socketClose 547 * Signature: ()V 548 */ 549 JNIEXPORT void JNICALL 550 Java_java_net_DualStackPlainSocketImpl_socketClose0(JNIEnv *env, jobject this, 551 jboolean useDeferredClose) { 552 553 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 554 jint fd=-1; 555 556 if (IS_NULL(fdObj)) { 557 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 558 "socket already closed"); 559 return; 560 } 561 if (!IS_NULL(fdObj)) { 562 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 563 } 564 if (fd != -1) { 565 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 566 NET_SocketClose(fd); 567 } 568 } 569 570 /* 571 * Class: java_net_DualStackPlainSocketImpl 572 * Method: socketShutdown 573 * Signature: (I)V 574 */ 575 JNIEXPORT void JNICALL 576 Java_java_net_DualStackPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this, 577 jint howto) 578 { 579 580 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 581 jint fd; 582 583 if (IS_NULL(fdObj)) { 584 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 585 "socket already closed"); 586 return; 587 } else { 588 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 589 } 590 shutdown(fd, howto); 591 } 592 593 /* 594 * Class: java_net_DualStackPlainSocketImpl 595 * Method: socketNativeSetOption 596 * Signature: (IZLjava/lang/Object;)V 597 */ 598 JNIEXPORT void JNICALL 599 Java_java_net_DualStackPlainSocketImpl_socketNativeSetOption 600 (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value) 601 { 602 /* The fd field */ 603 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 604 605 jint fd; 606 int level = 0, optname = 0, optlen = 0; 607 union { 608 int i; 609 struct linger ling; 610 } optval; 611 612 memset((char *)&optval, 0, sizeof(optval)); 613 614 /* 615 * Get SOCKET and check that it hasn't been closed 616 */ 617 if (IS_NULL(fdObj)) { 618 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 619 return; 620 } else { 621 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 622 } 623 if (fd < 0) { 624 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 625 return; 626 } 627 628 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 629 // timeout implemented through select. 630 return; 631 } 632 633 /* 634 * Map the Java level socket option to the platform specific 635 * level and option name. 636 */ 637 if (NET_MapSocketOption(cmd, &level, &optname)) { 638 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 639 return; 640 } 641 642 switch (cmd) { 643 644 case java_net_SocketOptions_TCP_NODELAY: 645 case java_net_SocketOptions_SO_OOBINLINE: 646 case java_net_SocketOptions_SO_KEEPALIVE: 647 case java_net_SocketOptions_SO_REUSEADDR: 648 optval.i = (on ? 1 : 0); 649 optlen = sizeof(optval.i); 650 break; 651 652 case java_net_SocketOptions_SO_SNDBUF: 653 case java_net_SocketOptions_SO_RCVBUF: 654 case java_net_SocketOptions_IP_TOS: 655 { 656 jclass cls; 657 jfieldID fid; 658 659 cls = (*env)->FindClass(env, "java/lang/Integer"); 660 CHECK_NULL(cls); 661 fid = (*env)->GetFieldID(env, cls, "value", "I"); 662 CHECK_NULL(fid); 663 664 optval.i = (*env)->GetIntField(env, value, fid); 665 optlen = sizeof(optval.i); 666 } 667 break; 668 669 case java_net_SocketOptions_SO_LINGER : 670 { 671 jclass cls; 672 jfieldID fid; 673 674 cls = (*env)->FindClass(env, "java/lang/Integer"); 675 CHECK_NULL(cls); 676 fid = (*env)->GetFieldID(env, cls, "value", "I"); 677 CHECK_NULL(fid); 678 679 if (on) { 680 optval.ling.l_onoff = 1; 681 optval.ling.l_linger = 682 (unsigned short)(*env)->GetIntField(env, value, fid); 683 } else { 684 optval.ling.l_onoff = 0; 685 optval.ling.l_linger = 0; 686 } 687 optlen = sizeof(optval.ling); 688 } 689 break; 690 691 default: /* shouldn't get here */ 692 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 693 "Option not supported by DualStackPlainSocketImpl"); 694 return; 695 } 696 697 if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) { 698 NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); 699 } 700 } 701 702 /* 703 * Class: java_net_DualStackPlainSocketImpl 704 * Method: socketNativeGetOption 705 * Signature: (ILjava/lang/Object;)I 706 */ 707 JNIEXPORT jint JNICALL 708 Java_java_net_DualStackPlainSocketImpl_socketNativeGetOption 709 (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj) 710 { 711 /* The fd field */ 712 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 713 714 int fd; 715 int level = 0, optname = 0, optlen = 0; 716 union { 717 int i; 718 struct linger ling; 719 } optval; 720 721 /* 722 * Get SOCKET and check it hasn't been closed 723 */ 724 if (IS_NULL(fdObj)) { 725 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 726 return -1; 727 } else { 728 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 729 } 730 if (fd < 0) { 731 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 732 return -1; 733 } 734 memset((char *)&optval, 0, sizeof(optval)); 735 736 /* 737 * SO_BINDADDR isn't a socket option 738 */ 739 if (opt == java_net_SocketOptions_SO_BINDADDR) { 740 SOCKETADDRESS sa; 741 int len = sizeof(sa); 742 int port; 743 jobject iaObj; 744 jclass iaContainerClass; 745 jfieldID iaFieldID; 746 747 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { 748 NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); 749 return -1; 750 } 751 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 752 CHECK_NULL_RETURN(iaObj, -1); 753 754 iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj); 755 iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;"); 756 CHECK_NULL_RETURN(iaFieldID, -1); 757 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 758 return 0; /* notice change from before */ 759 } 760 761 /* 762 * Map the Java level socket option to the platform specific 763 * level and option name. 764 */ 765 if (NET_MapSocketOption(opt, &level, &optname)) { 766 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 767 return -1; 768 } 769 770 /* 771 * Args are int except for SO_LINGER 772 */ 773 if (opt == java_net_SocketOptions_SO_LINGER) { 774 optlen = sizeof(optval.ling); 775 } else { 776 optlen = sizeof(optval.i); 777 optval.i = 0; 778 } 779 780 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 781 NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); 782 return -1; 783 } 784 785 switch (opt) { 786 case java_net_SocketOptions_SO_LINGER: 787 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 788 789 case java_net_SocketOptions_SO_SNDBUF: 790 case java_net_SocketOptions_SO_RCVBUF: 791 case java_net_SocketOptions_IP_TOS: 792 return optval.i; 793 794 case java_net_SocketOptions_TCP_NODELAY: 795 case java_net_SocketOptions_SO_OOBINLINE: 796 case java_net_SocketOptions_SO_KEEPALIVE: 797 case java_net_SocketOptions_SO_REUSEADDR: 798 return (optval.i == 0) ? -1 : 1; 799 800 default: /* shouldn't get here */ 801 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 802 "Option not supported by TwoStacksPlainSocketImpl"); 803 return -1; 804 } 805 } 806 807 /* 808 * Class: java_net_DualStackPlainSocketImpl 809 * Method: socketSendUrgentData 810 * Signature: (B)V 811 */ 812 JNIEXPORT void JNICALL 813 Java_java_net_DualStackPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this, 814 jint data) { 815 /* The fd field */ 816 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 817 int n, fd; 818 unsigned char d = (unsigned char) data & 0xff; 819 820 if (IS_NULL(fdObj)) { 821 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 822 return; 823 } else { 824 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 825 826 if (fd == -1) { 827 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 828 return; 829 } 830 831 } 832 n = send(fd, (char *)&data, 1, MSG_OOB); 833 if (n == SOCKET_ERROR) { 834 NET_ThrowNew(env, WSAGetLastError(), "send"); 835 } 836 }