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