< prev index next >

src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java

Print this page




  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.Set;
  39 
  40 import sun.net.ConnectionResetException;
  41 import sun.net.NetHooks;
  42 import sun.net.PlatformSocketImpl;
  43 import sun.net.ResourceManager;

  44 import sun.net.util.SocketExceptions;
  45 
  46 /**
  47  * Default Socket Implementation. This implementation does
  48  * not implement any security checks.
  49  * Note this class should <b>NOT</b> be public.
  50  *
  51  * @author  Steven B. Byrne
  52  */
  53 abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSocketImpl {
  54     /* instance variable for SO_TIMEOUT */
  55     int timeout;   // timeout in millisec
  56     // traffic class
  57     private int trafficClass;
  58 
  59     private boolean shut_rd = false;
  60     private boolean shut_wr = false;
  61 
  62     private SocketInputStream socketInputStream = null;
  63     private SocketOutputStream socketOutputStream = null;


  67 
  68     /* lock when increment/decrementing fdUseCount */
  69     protected final Object fdLock = new Object();
  70 
  71     /* indicates a close is pending on the file descriptor */
  72     protected boolean closePending = false;
  73 
  74     /* indicates connection reset state */
  75     private volatile boolean connectionReset;
  76 
  77     /* indicates whether impl is bound  */
  78     boolean isBound;
  79 
  80     /* indicates whether impl is connected  */
  81     volatile boolean isConnected;
  82 
  83    /* whether this Socket is a stream (TCP) socket or not (UDP)
  84     */
  85     protected boolean stream;
  86 



  87     /**
  88      * Load net library into runtime.
  89      */
  90     static {
  91         java.security.AccessController.doPrivileged(
  92             new java.security.PrivilegedAction<>() {
  93                 public Void run() {
  94                     System.loadLibrary("net");
  95                     return null;
  96                 }
  97             });
  98     }
  99 
 100     private static volatile boolean checkedReusePort;
 101     private static volatile boolean isReusePortAvailable;
 102 
 103     /**
 104      * Tells whether SO_REUSEPORT is supported.
 105      */
 106     static boolean isReusePortAvailable() {
 107         if (!checkedReusePort) {
 108             isReusePortAvailable = isReusePortAvailable0();
 109             checkedReusePort = true;
 110         }
 111         return isReusePortAvailable;
 112     }
 113 
 114     AbstractPlainSocketImpl(boolean isServer) {
 115         super(isServer);
 116     }
 117 
 118     /**
 119      * Returns a set of SocketOptions supported by this impl and by this impl's
 120      * socket (Socket or ServerSocket)
 121      *
 122      * @return a Set of SocketOptions
 123      */
 124     @Override
 125     protected Set<SocketOption<?>> supportedOptions() {
 126         Set<SocketOption<?>> options;
 127         if (isReusePortAvailable()) {
 128             options = new HashSet<>();
 129             options.addAll(super.supportedOptions());
 130             options.add(StandardSocketOptions.SO_REUSEPORT);
 131             options = Collections.unmodifiableSet(options);
 132         } else {
 133             options = super.supportedOptions();
 134         }
 135         return options;
 136     }
 137 
 138     /**
 139      * Creates a socket with a boolean that specifies whether this
 140      * is a stream socket (true) or an unconnected UDP socket (false).
 141      */
 142     protected synchronized void create(boolean stream) throws IOException {
 143         this.stream = stream;
 144         if (!stream) {
 145             ResourceManager.beforeUdpCreate();
 146             // only create the fd after we know we will be able to create the socket
 147             fd = new FileDescriptor();
 148             try {
 149                 socketCreate(false);
 150                 SocketCleanable.register(fd);
 151             } catch (IOException ioe) {
 152                 ResourceManager.afterUdpClose();
 153                 fd = null;
 154                 throw ioe;
 155             }


 374                     return trafficClass;
 375                 } else {
 376                     return ret;
 377                 }
 378             } catch (SocketException se) {
 379                     // TODO - should make better effort to read TOS or TCLASS
 380                     return trafficClass; // ipv6 tos
 381             }
 382         case SO_KEEPALIVE:
 383             ret = socketGetOption(opt, null);
 384             return Boolean.valueOf(ret != -1);
 385         case SO_REUSEPORT:
 386             if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
 387                 throw new UnsupportedOperationException("unsupported option");
 388             }
 389             ret = socketGetOption(opt, null);
 390             return Boolean.valueOf(ret != -1);
 391         // should never get here
 392         default:
 393             return null;



















































































































 394         }
 395     }
 396 
 397     /**
 398      * The workhorse of the connection operation.  Tries several times to
 399      * establish a connection to the given <host, port>.  If unsuccessful,
 400      * throws an IOException indicating what went wrong.
 401      */
 402 
 403     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
 404         synchronized (fdLock) {
 405             if (!closePending && !isBound) {
 406                 NetHooks.beforeTcpConnect(fd, address, port);
 407             }
 408         }
 409         try {
 410             acquireFD();
 411             try {
 412                 socketConnect(address, port, timeout);
 413                 /* socket may have been closed during poll/select */




  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;


  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             }


 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 */


< prev index next >