1 /* 2 * Copyright (c) 1995, 2019, 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 package java.net; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 33 import java.security.AccessController; 34 import java.security.PrivilegedActionException; 35 import java.security.PrivilegedExceptionAction; 36 import java.util.Collections; 37 import java.util.HashSet; 38 import java.util.Objects; 39 import java.util.Set; 40 41 import sun.net.ConnectionResetException; 42 import sun.net.NetHooks; 43 import sun.net.PlatformSocketImpl; 44 import sun.net.ResourceManager; 45 import sun.net.ext.ExtendedSocketOptions; 46 import sun.net.util.SocketExceptions; 47 48 /** 49 * Default Socket Implementation. This implementation does 50 * not implement any security checks. 51 * Note this class should <b>NOT</b> be public. 52 * 53 * @author Steven B. Byrne 54 */ 55 abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSocketImpl { 56 /* instance variable for SO_TIMEOUT */ 57 int timeout; // timeout in millisec 58 // traffic class 59 private int trafficClass; 60 61 private boolean shut_rd = false; 62 private boolean shut_wr = false; 63 64 private SocketInputStream socketInputStream = null; 65 private SocketOutputStream socketOutputStream = null; 66 67 /* number of threads using the FileDescriptor */ 68 protected int fdUseCount = 0; 69 70 /* lock when increment/decrementing fdUseCount */ 71 protected final Object fdLock = new Object(); 72 73 /* indicates a close is pending on the file descriptor */ 74 protected boolean closePending = false; 75 76 /* indicates connection reset state */ 77 private volatile boolean connectionReset; 78 79 /* indicates whether impl is bound */ 80 boolean isBound; 81 82 /* indicates whether impl is connected */ 83 volatile boolean isConnected; 84 85 /* whether this Socket is a stream (TCP) socket or not (UDP) 86 */ 87 protected boolean stream; 88 89 /* whether this is a server or not */ 90 final boolean isServer; 91 92 /** 93 * Load net library into runtime. 94 */ 95 static { 96 java.security.AccessController.doPrivileged( 97 new java.security.PrivilegedAction<>() { 98 public Void run() { 99 System.loadLibrary("net"); 100 return null; 101 } 102 }); 103 } 104 105 private static volatile boolean checkedReusePort; 106 private static volatile boolean isReusePortAvailable; 107 108 /** 109 * Tells whether SO_REUSEPORT is supported. 110 */ 111 static boolean isReusePortAvailable() { 112 if (!checkedReusePort) { 113 isReusePortAvailable = isReusePortAvailable0(); 114 checkedReusePort = true; 115 } 116 return isReusePortAvailable; 117 } 118 119 AbstractPlainSocketImpl(boolean isServer) { 120 this.isServer = isServer; 121 } 122 123 /** 124 * Creates a socket with a boolean that specifies whether this 125 * is a stream socket (true) or an unconnected UDP socket (false). 126 */ 127 protected synchronized void create(boolean stream) throws IOException { 128 this.stream = stream; 129 if (!stream) { 130 ResourceManager.beforeUdpCreate(); 131 // only create the fd after we know we will be able to create the socket 132 fd = new FileDescriptor(); 133 try { 134 socketCreate(false); 135 SocketCleanable.register(fd); 136 } catch (IOException ioe) { 137 ResourceManager.afterUdpClose(); 138 fd = null; 139 throw ioe; 140 } 141 } else { 142 fd = new FileDescriptor(); 143 socketCreate(true); 144 SocketCleanable.register(fd); 145 } 146 } 147 148 /** 149 * Creates a socket and connects it to the specified port on 150 * the specified host. 151 * @param host the specified host 152 * @param port the specified port 153 */ 154 protected void connect(String host, int port) 155 throws UnknownHostException, IOException 156 { 157 boolean connected = false; 158 try { 159 InetAddress address = InetAddress.getByName(host); 160 this.port = port; 161 this.address = address; 162 163 connectToAddress(address, port, timeout); 164 connected = true; 165 } finally { 166 if (!connected) { 167 try { 168 close(); 169 } catch (IOException ioe) { 170 /* Do nothing. If connect threw an exception then 171 it will be passed up the call stack */ 172 } 173 } 174 isConnected = connected; 175 } 176 } 177 178 /** 179 * Creates a socket and connects it to the specified address on 180 * the specified port. 181 * @param address the address 182 * @param port the specified port 183 */ 184 protected void connect(InetAddress address, int port) throws IOException { 185 this.port = port; 186 this.address = address; 187 188 try { 189 connectToAddress(address, port, timeout); 190 isConnected = true; 191 return; 192 } catch (IOException e) { 193 // everything failed 194 close(); 195 throw e; 196 } 197 } 198 199 /** 200 * Creates a socket and connects it to the specified address on 201 * the specified port. 202 * @param address the address 203 * @param timeout the timeout value in milliseconds, or zero for no timeout. 204 * @throws IOException if connection fails 205 * @throws IllegalArgumentException if address is null or is a 206 * SocketAddress subclass not supported by this socket 207 * @since 1.4 208 */ 209 protected void connect(SocketAddress address, int timeout) 210 throws IOException { 211 boolean connected = false; 212 try { 213 if (address == null || !(address instanceof InetSocketAddress)) 214 throw new IllegalArgumentException("unsupported address type"); 215 InetSocketAddress addr = (InetSocketAddress) address; 216 if (addr.isUnresolved()) 217 throw new UnknownHostException(addr.getHostName()); 218 this.port = addr.getPort(); 219 this.address = addr.getAddress(); 220 221 connectToAddress(this.address, port, timeout); 222 connected = true; 223 } finally { 224 if (!connected) { 225 try { 226 close(); 227 } catch (IOException ioe) { 228 /* Do nothing. If connect threw an exception then 229 it will be passed up the call stack */ 230 } 231 } 232 isConnected = connected; 233 } 234 } 235 236 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { 237 if (address.isAnyLocalAddress()) { 238 doConnect(InetAddress.getLocalHost(), port, timeout); 239 } else { 240 doConnect(address, port, timeout); 241 } 242 } 243 244 public void setOption(int opt, Object val) throws SocketException { 245 if (isClosedOrPending()) { 246 throw new SocketException("Socket Closed"); 247 } 248 boolean on = true; 249 switch (opt) { 250 /* check type safety b4 going native. These should never 251 * fail, since only java.Socket* has access to 252 * PlainSocketImpl.setOption(). 253 */ 254 case SO_LINGER: 255 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) 256 throw new SocketException("Bad parameter for option"); 257 if (val instanceof Boolean) { 258 /* true only if disabling - enabling should be Integer */ 259 on = false; 260 } 261 break; 262 case SO_TIMEOUT: 263 if (val == null || (!(val instanceof Integer))) 264 throw new SocketException("Bad parameter for SO_TIMEOUT"); 265 int tmp = ((Integer) val).intValue(); 266 if (tmp < 0) 267 throw new IllegalArgumentException("timeout < 0"); 268 timeout = tmp; 269 break; 270 case IP_TOS: 271 if (val == null || !(val instanceof Integer)) { 272 throw new SocketException("bad argument for IP_TOS"); 273 } 274 trafficClass = ((Integer)val).intValue(); 275 break; 276 case SO_BINDADDR: 277 throw new SocketException("Cannot re-bind socket"); 278 case TCP_NODELAY: 279 if (val == null || !(val instanceof Boolean)) 280 throw new SocketException("bad parameter for TCP_NODELAY"); 281 on = ((Boolean)val).booleanValue(); 282 break; 283 case SO_SNDBUF: 284 case SO_RCVBUF: 285 if (val == null || !(val instanceof Integer) || 286 !(((Integer)val).intValue() > 0)) { 287 throw new SocketException("bad parameter for SO_SNDBUF " + 288 "or SO_RCVBUF"); 289 } 290 break; 291 case SO_KEEPALIVE: 292 if (val == null || !(val instanceof Boolean)) 293 throw new SocketException("bad parameter for SO_KEEPALIVE"); 294 on = ((Boolean)val).booleanValue(); 295 break; 296 case SO_OOBINLINE: 297 if (val == null || !(val instanceof Boolean)) 298 throw new SocketException("bad parameter for SO_OOBINLINE"); 299 on = ((Boolean)val).booleanValue(); 300 break; 301 case SO_REUSEADDR: 302 if (val == null || !(val instanceof Boolean)) 303 throw new SocketException("bad parameter for SO_REUSEADDR"); 304 on = ((Boolean)val).booleanValue(); 305 break; 306 case SO_REUSEPORT: 307 if (val == null || !(val instanceof Boolean)) 308 throw new SocketException("bad parameter for SO_REUSEPORT"); 309 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) 310 throw new UnsupportedOperationException("unsupported option"); 311 on = ((Boolean)val).booleanValue(); 312 break; 313 default: 314 throw new SocketException("unrecognized TCP option: " + opt); 315 } 316 socketSetOption(opt, on, val); 317 } 318 public Object getOption(int opt) throws SocketException { 319 if (isClosedOrPending()) { 320 throw new SocketException("Socket Closed"); 321 } 322 if (opt == SO_TIMEOUT) { 323 return timeout; 324 } 325 int ret = 0; 326 /* 327 * The native socketGetOption() knows about 3 options. 328 * The 32 bit value it returns will be interpreted according 329 * to what we're asking. A return of -1 means it understands 330 * the option but its turned off. It will raise a SocketException 331 * if "opt" isn't one it understands. 332 */ 333 334 switch (opt) { 335 case TCP_NODELAY: 336 ret = socketGetOption(opt, null); 337 return Boolean.valueOf(ret != -1); 338 case SO_OOBINLINE: 339 ret = socketGetOption(opt, null); 340 return Boolean.valueOf(ret != -1); 341 case SO_LINGER: 342 ret = socketGetOption(opt, null); 343 return (ret == -1) ? Boolean.FALSE: (Object)(ret); 344 case SO_REUSEADDR: 345 ret = socketGetOption(opt, null); 346 return Boolean.valueOf(ret != -1); 347 case SO_BINDADDR: 348 InetAddressContainer in = new InetAddressContainer(); 349 ret = socketGetOption(opt, in); 350 return in.addr; 351 case SO_SNDBUF: 352 case SO_RCVBUF: 353 ret = socketGetOption(opt, null); 354 return ret; 355 case IP_TOS: 356 try { 357 ret = socketGetOption(opt, null); 358 if (ret == -1) { // ipv6 tos 359 return trafficClass; 360 } else { 361 return ret; 362 } 363 } catch (SocketException se) { 364 // TODO - should make better effort to read TOS or TCLASS 365 return trafficClass; // ipv6 tos 366 } 367 case SO_KEEPALIVE: 368 ret = socketGetOption(opt, null); 369 return Boolean.valueOf(ret != -1); 370 case SO_REUSEPORT: 371 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 372 throw new UnsupportedOperationException("unsupported option"); 373 } 374 ret = socketGetOption(opt, null); 375 return Boolean.valueOf(ret != -1); 376 // should never get here 377 default: 378 return null; 379 } 380 } 381 382 static final ExtendedSocketOptions extendedOptions = 383 ExtendedSocketOptions.getInstance(); 384 385 private static final Set<SocketOption<?>> clientSocketOptions = clientSocketOptions(); 386 private static final Set<SocketOption<?>> serverSocketOptions = serverSocketOptions(); 387 388 private static Set<SocketOption<?>> clientSocketOptions() { 389 HashSet<SocketOption<?>> options = new HashSet<>(); 390 options.add(StandardSocketOptions.SO_KEEPALIVE); 391 options.add(StandardSocketOptions.SO_SNDBUF); 392 options.add(StandardSocketOptions.SO_RCVBUF); 393 options.add(StandardSocketOptions.SO_REUSEADDR); 394 options.add(StandardSocketOptions.SO_LINGER); 395 options.add(StandardSocketOptions.IP_TOS); 396 options.add(StandardSocketOptions.TCP_NODELAY); 397 if (isReusePortAvailable()) 398 options.add(StandardSocketOptions.SO_REUSEPORT); 399 options.addAll(ExtendedSocketOptions.clientSocketOptions()); 400 return Collections.unmodifiableSet(options); 401 } 402 403 private static Set<SocketOption<?>> serverSocketOptions() { 404 HashSet<SocketOption<?>> options = new HashSet<>(); 405 options.add(StandardSocketOptions.SO_RCVBUF); 406 options.add(StandardSocketOptions.SO_REUSEADDR); 407 options.add(StandardSocketOptions.IP_TOS); 408 if (isReusePortAvailable()) 409 options.add(StandardSocketOptions.SO_REUSEPORT); 410 options.addAll(ExtendedSocketOptions.serverSocketOptions()); 411 return Collections.unmodifiableSet(options); 412 } 413 414 @Override 415 protected Set<SocketOption<?>> supportedOptions() { 416 if (isServer) 417 return serverSocketOptions; 418 else 419 return clientSocketOptions; 420 } 421 422 @Override 423 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { 424 Objects.requireNonNull(name); 425 if (!supportedOptions().contains(name)) 426 throw new UnsupportedOperationException("'" + name + "' not supported"); 427 428 if (!name.type().isInstance(value)) 429 throw new IllegalArgumentException("Invalid value '" + value + "'"); 430 431 if (isClosedOrPending()) 432 throw new SocketException("Socket closed"); 433 434 if (name == StandardSocketOptions.SO_KEEPALIVE) { 435 setOption(SocketOptions.SO_KEEPALIVE, value); 436 } else if (name == StandardSocketOptions.SO_SNDBUF) { 437 if (((Integer)value).intValue() < 0) 438 throw new IllegalArgumentException("Invalid send buffer size:" + value); 439 setOption(SocketOptions.SO_SNDBUF, value); 440 } else if (name == StandardSocketOptions.SO_RCVBUF) { 441 if (((Integer)value).intValue() < 0) 442 throw new IllegalArgumentException("Invalid recv buffer size:" + value); 443 setOption(SocketOptions.SO_RCVBUF, value); 444 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 445 setOption(SocketOptions.SO_REUSEADDR, value); 446 } else if (name == StandardSocketOptions.SO_REUSEPORT) { 447 setOption(SocketOptions.SO_REUSEPORT, value); 448 } else if (name == StandardSocketOptions.SO_LINGER ) { 449 setOption(SocketOptions.SO_LINGER, value); 450 } else if (name == StandardSocketOptions.IP_TOS) { 451 int i = ((Integer)value).intValue(); 452 if (i < 0 || i > 255) 453 throw new IllegalArgumentException("Invalid IP_TOS value: " + value); 454 setOption(SocketOptions.IP_TOS, value); 455 } else if (name == StandardSocketOptions.TCP_NODELAY) { 456 setOption(SocketOptions.TCP_NODELAY, value); 457 } else if (extendedOptions.isOptionSupported(name)) { 458 extendedOptions.setOption(fd, name, value); 459 } else { 460 throw new AssertionError("unknown option: " + name); 461 } 462 } 463 464 @Override 465 @SuppressWarnings("unchecked") 466 protected <T> T getOption(SocketOption<T> name) throws IOException { 467 Objects.requireNonNull(name); 468 if (!supportedOptions().contains(name)) 469 throw new UnsupportedOperationException("'" + name + "' not supported"); 470 471 if (isClosedOrPending()) 472 throw new SocketException("Socket closed"); 473 474 if (name == StandardSocketOptions.SO_KEEPALIVE) { 475 return (T)getOption(SocketOptions.SO_KEEPALIVE); 476 } else if (name == StandardSocketOptions.SO_SNDBUF) { 477 return (T)getOption(SocketOptions.SO_SNDBUF); 478 } else if (name == StandardSocketOptions.SO_RCVBUF) { 479 return (T)getOption(SocketOptions.SO_RCVBUF); 480 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 481 return (T)getOption(SocketOptions.SO_REUSEADDR); 482 } else if (name == StandardSocketOptions.SO_REUSEPORT) { 483 return (T)getOption(SocketOptions.SO_REUSEPORT); 484 } else if (name == StandardSocketOptions.SO_LINGER) { 485 return (T)getOption(SocketOptions.SO_LINGER); 486 } else if (name == StandardSocketOptions.IP_TOS) { 487 return (T)getOption(SocketOptions.IP_TOS); 488 } else if (name == StandardSocketOptions.TCP_NODELAY) { 489 return (T)getOption(SocketOptions.TCP_NODELAY); 490 } else if (extendedOptions.isOptionSupported(name)) { 491 return (T) extendedOptions.getOption(fd, name); 492 } else { 493 throw new AssertionError("unknown option: " + name); 494 } 495 } 496 497 /** 498 * The workhorse of the connection operation. Tries several times to 499 * establish a connection to the given <host, port>. If unsuccessful, 500 * throws an IOException indicating what went wrong. 501 */ 502 503 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 504 synchronized (fdLock) { 505 if (!closePending && !isBound) { 506 NetHooks.beforeTcpConnect(fd, address, port); 507 } 508 } 509 try { 510 acquireFD(); 511 try { 512 socketConnect(address, port, timeout); 513 /* socket may have been closed during poll/select */ 514 synchronized (fdLock) { 515 if (closePending) { 516 throw new SocketException ("Socket closed"); 517 } 518 } 519 } finally { 520 releaseFD(); 521 } 522 } catch (IOException e) { 523 close(); 524 throw SocketExceptions.of(e, new InetSocketAddress(address, port)); 525 } 526 } 527 528 /** 529 * Binds the socket to the specified address of the specified local port. 530 * @param address the address 531 * @param lport the port 532 */ 533 protected synchronized void bind(InetAddress address, int lport) 534 throws IOException 535 { 536 synchronized (fdLock) { 537 if (!closePending && !isBound) { 538 NetHooks.beforeTcpBind(fd, address, lport); 539 } 540 } 541 socketBind(address, lport); 542 isBound = true; 543 } 544 545 /** 546 * Listens, for a specified amount of time, for connections. 547 * @param count the amount of time to listen for connections 548 */ 549 protected synchronized void listen(int count) throws IOException { 550 socketListen(count); 551 } 552 553 /** 554 * Accepts connections. 555 * @param si the socket impl 556 */ 557 protected void accept(SocketImpl si) throws IOException { 558 si.fd = new FileDescriptor(); 559 acquireFD(); 560 try { 561 socketAccept(si); 562 } finally { 563 releaseFD(); 564 } 565 SocketCleanable.register(si.fd); 566 } 567 568 /** 569 * Gets an InputStream for this socket. 570 */ 571 protected synchronized InputStream getInputStream() throws IOException { 572 synchronized (fdLock) { 573 if (isClosedOrPending()) 574 throw new IOException("Socket Closed"); 575 if (shut_rd) 576 throw new IOException("Socket input is shutdown"); 577 if (socketInputStream == null) { 578 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this); 579 try { 580 socketInputStream = AccessController.doPrivileged(pa); 581 } catch (PrivilegedActionException e) { 582 throw (IOException) e.getCause(); 583 } 584 } 585 } 586 return socketInputStream; 587 } 588 589 void setInputStream(SocketInputStream in) { 590 socketInputStream = in; 591 } 592 593 /** 594 * Gets an OutputStream for this socket. 595 */ 596 protected synchronized OutputStream getOutputStream() throws IOException { 597 synchronized (fdLock) { 598 if (isClosedOrPending()) 599 throw new IOException("Socket Closed"); 600 if (shut_wr) 601 throw new IOException("Socket output is shutdown"); 602 if (socketOutputStream == null) { 603 PrivilegedExceptionAction<SocketOutputStream> pa = () -> new SocketOutputStream(this); 604 try { 605 socketOutputStream = AccessController.doPrivileged(pa); 606 } catch (PrivilegedActionException e) { 607 throw (IOException) e.getCause(); 608 } 609 } 610 } 611 return socketOutputStream; 612 } 613 614 void setFileDescriptor(FileDescriptor fd) { 615 this.fd = fd; 616 } 617 618 void setAddress(InetAddress address) { 619 this.address = address; 620 } 621 622 void setPort(int port) { 623 this.port = port; 624 } 625 626 void setLocalPort(int localport) { 627 this.localport = localport; 628 } 629 630 /** 631 * Returns the number of bytes that can be read without blocking. 632 */ 633 protected synchronized int available() throws IOException { 634 if (isClosedOrPending()) { 635 throw new IOException("Stream closed."); 636 } 637 638 /* 639 * If connection has been reset or shut down for input, then return 0 640 * to indicate there are no buffered bytes. 641 */ 642 if (isConnectionReset() || shut_rd) { 643 return 0; 644 } 645 646 /* 647 * If no bytes available and we were previously notified 648 * of a connection reset then we move to the reset state. 649 * 650 * If are notified of a connection reset then check 651 * again if there are bytes buffered on the socket. 652 */ 653 int n = 0; 654 try { 655 n = socketAvailable(); 656 } catch (ConnectionResetException exc1) { 657 setConnectionReset(); 658 } 659 return n; 660 } 661 662 /** 663 * Closes the socket. 664 */ 665 protected void close() throws IOException { 666 synchronized(fdLock) { 667 if (fd != null) { 668 if (!stream) { 669 ResourceManager.afterUdpClose(); 670 } 671 if (fdUseCount == 0) { 672 if (closePending) { 673 return; 674 } 675 closePending = true; 676 /* 677 * We close the FileDescriptor in two-steps - first the 678 * "pre-close" which closes the socket but doesn't 679 * release the underlying file descriptor. This operation 680 * may be lengthy due to untransmitted data and a long 681 * linger interval. Once the pre-close is done we do the 682 * actual socket to release the fd. 683 */ 684 try { 685 socketPreClose(); 686 } finally { 687 socketClose(); 688 } 689 fd = null; 690 return; 691 } else { 692 /* 693 * If a thread has acquired the fd and a close 694 * isn't pending then use a deferred close. 695 * Also decrement fdUseCount to signal the last 696 * thread that releases the fd to close it. 697 */ 698 if (!closePending) { 699 closePending = true; 700 fdUseCount--; 701 socketPreClose(); 702 } 703 } 704 } 705 } 706 } 707 708 void reset() { 709 throw new InternalError("should not get here"); 710 } 711 712 /** 713 * Shutdown read-half of the socket connection; 714 */ 715 protected void shutdownInput() throws IOException { 716 if (fd != null) { 717 socketShutdown(SHUT_RD); 718 if (socketInputStream != null) { 719 socketInputStream.setEOF(true); 720 } 721 shut_rd = true; 722 } 723 } 724 725 /** 726 * Shutdown write-half of the socket connection; 727 */ 728 protected void shutdownOutput() throws IOException { 729 if (fd != null) { 730 socketShutdown(SHUT_WR); 731 shut_wr = true; 732 } 733 } 734 735 protected boolean supportsUrgentData () { 736 return true; 737 } 738 739 protected void sendUrgentData (int data) throws IOException { 740 if (fd == null) { 741 throw new IOException("Socket Closed"); 742 } 743 socketSendUrgentData (data); 744 } 745 746 /* 747 * "Acquires" and returns the FileDescriptor for this impl 748 * 749 * A corresponding releaseFD is required to "release" the 750 * FileDescriptor. 751 */ 752 FileDescriptor acquireFD() { 753 synchronized (fdLock) { 754 fdUseCount++; 755 return fd; 756 } 757 } 758 759 /* 760 * "Release" the FileDescriptor for this impl. 761 * 762 * If the use count goes to -1 then the socket is closed. 763 */ 764 void releaseFD() { 765 synchronized (fdLock) { 766 fdUseCount--; 767 if (fdUseCount == -1) { 768 if (fd != null) { 769 try { 770 socketClose(); 771 } catch (IOException e) { 772 } finally { 773 fd = null; 774 } 775 } 776 } 777 } 778 } 779 780 boolean isConnectionReset() { 781 return connectionReset; 782 } 783 784 void setConnectionReset() { 785 connectionReset = true; 786 } 787 788 /* 789 * Return true if already closed or close is pending 790 */ 791 public boolean isClosedOrPending() { 792 /* 793 * Lock on fdLock to ensure that we wait if a 794 * close is in progress. 795 */ 796 synchronized (fdLock) { 797 if (closePending || (fd == null)) { 798 return true; 799 } else { 800 return false; 801 } 802 } 803 } 804 805 /* 806 * Return the current value of SO_TIMEOUT 807 */ 808 public int getTimeout() { 809 return timeout; 810 } 811 812 /* 813 * "Pre-close" a socket by dup'ing the file descriptor - this enables 814 * the socket to be closed without releasing the file descriptor. 815 */ 816 private void socketPreClose() throws IOException { 817 socketClose0(true); 818 } 819 820 /* 821 * Close the socket (and release the file descriptor). 822 */ 823 protected void socketClose() throws IOException { 824 SocketCleanable.unregister(fd); 825 socketClose0(false); 826 } 827 828 abstract void socketCreate(boolean stream) throws IOException; 829 abstract void socketConnect(InetAddress address, int port, int timeout) 830 throws IOException; 831 abstract void socketBind(InetAddress address, int port) 832 throws IOException; 833 abstract void socketListen(int count) 834 throws IOException; 835 abstract void socketAccept(SocketImpl s) 836 throws IOException; 837 abstract int socketAvailable() 838 throws IOException; 839 abstract void socketClose0(boolean useDeferredClose) 840 throws IOException; 841 abstract void socketShutdown(int howto) 842 throws IOException; 843 abstract void socketSetOption(int cmd, boolean on, Object value) 844 throws SocketException; 845 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; 846 abstract void socketSendUrgentData(int data) 847 throws IOException; 848 849 public static final int SHUT_RD = 0; 850 public static final int SHUT_WR = 1; 851 852 private static native boolean isReusePortAvailable0(); 853 }