Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java
38829 views
/*1* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.net;2627import java.io.IOException;28import java.io.InputStream;29import java.io.OutputStream;30import java.io.FileDescriptor;3132import sun.net.ConnectionResetException;33import sun.net.NetHooks;34import sun.net.ResourceManager;3536/**37* Default Socket Implementation. This implementation does38* not implement any security checks.39* Note this class should <b>NOT</b> be public.40*41* @author Steven B. Byrne42*/43abstract class AbstractPlainSocketImpl extends SocketImpl44{45/* instance variable for SO_TIMEOUT */46int timeout; // timeout in millisec47// traffic class48private int trafficClass;4950private boolean shut_rd = false;51private boolean shut_wr = false;5253private SocketInputStream socketInputStream = null;54private SocketOutputStream socketOutputStream = null;5556/* number of threads using the FileDescriptor */57protected int fdUseCount = 0;5859/* lock when increment/decrementing fdUseCount */60protected final Object fdLock = new Object();6162/* indicates a close is pending on the file descriptor */63protected boolean closePending = false;6465/* indicates connection reset state */66private int CONNECTION_NOT_RESET = 0;67private int CONNECTION_RESET_PENDING = 1;68private int CONNECTION_RESET = 2;69private int resetState;70private final Object resetLock = new Object();7172/* whether this Socket is a stream (TCP) socket or not (UDP)73*/74protected boolean stream;7576/**77* Load net library into runtime.78*/79static {80java.security.AccessController.doPrivileged(81new java.security.PrivilegedAction<Void>() {82public Void run() {83System.loadLibrary("net");84return null;85}86});87}8889/**90* Creates a socket with a boolean that specifies whether this91* is a stream socket (true) or an unconnected UDP socket (false).92*/93protected synchronized void create(boolean stream) throws IOException {94this.stream = stream;95if (!stream) {96ResourceManager.beforeUdpCreate();97// only create the fd after we know we will be able to create the socket98fd = new FileDescriptor();99try {100socketCreate(false);101} catch (IOException ioe) {102ResourceManager.afterUdpClose();103fd = null;104throw ioe;105}106} else {107fd = new FileDescriptor();108socketCreate(true);109}110if (socket != null)111socket.setCreated();112if (serverSocket != null)113serverSocket.setCreated();114}115116/**117* Creates a socket and connects it to the specified port on118* the specified host.119* @param host the specified host120* @param port the specified port121*/122protected void connect(String host, int port)123throws UnknownHostException, IOException124{125boolean connected = false;126try {127InetAddress address = InetAddress.getByName(host);128this.port = port;129this.address = address;130131connectToAddress(address, port, timeout);132connected = true;133} finally {134if (!connected) {135try {136close();137} catch (IOException ioe) {138/* Do nothing. If connect threw an exception then139it will be passed up the call stack */140}141}142}143}144145/**146* Creates a socket and connects it to the specified address on147* the specified port.148* @param address the address149* @param port the specified port150*/151protected void connect(InetAddress address, int port) throws IOException {152this.port = port;153this.address = address;154155try {156connectToAddress(address, port, timeout);157return;158} catch (IOException e) {159// everything failed160close();161throw e;162}163}164165/**166* Creates a socket and connects it to the specified address on167* the specified port.168* @param address the address169* @param timeout the timeout value in milliseconds, or zero for no timeout.170* @throws IOException if connection fails171* @throws IllegalArgumentException if address is null or is a172* SocketAddress subclass not supported by this socket173* @since 1.4174*/175protected void connect(SocketAddress address, int timeout)176throws IOException {177boolean connected = false;178try {179if (address == null || !(address instanceof InetSocketAddress))180throw new IllegalArgumentException("unsupported address type");181InetSocketAddress addr = (InetSocketAddress) address;182if (addr.isUnresolved())183throw new UnknownHostException(addr.getHostName());184this.port = addr.getPort();185this.address = addr.getAddress();186187connectToAddress(this.address, port, timeout);188connected = true;189} finally {190if (!connected) {191try {192close();193} catch (IOException ioe) {194/* Do nothing. If connect threw an exception then195it will be passed up the call stack */196}197}198}199}200201private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {202if (address.isAnyLocalAddress()) {203doConnect(InetAddress.getLocalHost(), port, timeout);204} else {205doConnect(address, port, timeout);206}207}208209public void setOption(int opt, Object val) throws SocketException {210if (isClosedOrPending()) {211throw new SocketException("Socket Closed");212}213boolean on = true;214switch (opt) {215/* check type safety b4 going native. These should never216* fail, since only java.Socket* has access to217* PlainSocketImpl.setOption().218*/219case SO_LINGER:220if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))221throw new SocketException("Bad parameter for option");222if (val instanceof Boolean) {223/* true only if disabling - enabling should be Integer */224on = false;225}226break;227case SO_TIMEOUT:228if (val == null || (!(val instanceof Integer)))229throw new SocketException("Bad parameter for SO_TIMEOUT");230int tmp = ((Integer) val).intValue();231if (tmp < 0)232throw new IllegalArgumentException("timeout < 0");233timeout = tmp;234break;235case IP_TOS:236if (val == null || !(val instanceof Integer)) {237throw new SocketException("bad argument for IP_TOS");238}239trafficClass = ((Integer)val).intValue();240break;241case SO_BINDADDR:242throw new SocketException("Cannot re-bind socket");243case TCP_NODELAY:244if (val == null || !(val instanceof Boolean))245throw new SocketException("bad parameter for TCP_NODELAY");246on = ((Boolean)val).booleanValue();247break;248case SO_SNDBUF:249case SO_RCVBUF:250if (val == null || !(val instanceof Integer) ||251!(((Integer)val).intValue() > 0)) {252throw new SocketException("bad parameter for SO_SNDBUF " +253"or SO_RCVBUF");254}255break;256case SO_KEEPALIVE:257if (val == null || !(val instanceof Boolean))258throw new SocketException("bad parameter for SO_KEEPALIVE");259on = ((Boolean)val).booleanValue();260break;261case SO_OOBINLINE:262if (val == null || !(val instanceof Boolean))263throw new SocketException("bad parameter for SO_OOBINLINE");264on = ((Boolean)val).booleanValue();265break;266case SO_REUSEADDR:267if (val == null || !(val instanceof Boolean))268throw new SocketException("bad parameter for SO_REUSEADDR");269on = ((Boolean)val).booleanValue();270break;271default:272throw new SocketException("unrecognized TCP option: " + opt);273}274socketSetOption(opt, on, val);275}276public Object getOption(int opt) throws SocketException {277if (isClosedOrPending()) {278throw new SocketException("Socket Closed");279}280if (opt == SO_TIMEOUT) {281return new Integer(timeout);282}283int ret = 0;284/*285* The native socketGetOption() knows about 3 options.286* The 32 bit value it returns will be interpreted according287* to what we're asking. A return of -1 means it understands288* the option but its turned off. It will raise a SocketException289* if "opt" isn't one it understands.290*/291292switch (opt) {293case TCP_NODELAY:294ret = socketGetOption(opt, null);295return Boolean.valueOf(ret != -1);296case SO_OOBINLINE:297ret = socketGetOption(opt, null);298return Boolean.valueOf(ret != -1);299case SO_LINGER:300ret = socketGetOption(opt, null);301return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));302case SO_REUSEADDR:303ret = socketGetOption(opt, null);304return Boolean.valueOf(ret != -1);305case SO_BINDADDR:306InetAddressContainer in = new InetAddressContainer();307ret = socketGetOption(opt, in);308return in.addr;309case SO_SNDBUF:310case SO_RCVBUF:311ret = socketGetOption(opt, null);312return new Integer(ret);313case IP_TOS:314try {315ret = socketGetOption(opt, null);316if (ret == -1) { // ipv6 tos317return trafficClass;318} else {319return ret;320}321} catch (SocketException se) {322// TODO - should make better effort to read TOS or TCLASS323return trafficClass; // ipv6 tos324}325case SO_KEEPALIVE:326ret = socketGetOption(opt, null);327return Boolean.valueOf(ret != -1);328// should never get here329default:330return null;331}332}333334/**335* The workhorse of the connection operation. Tries several times to336* establish a connection to the given <host, port>. If unsuccessful,337* throws an IOException indicating what went wrong.338*/339340synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {341synchronized (fdLock) {342if (!closePending && (socket == null || !socket.isBound())) {343NetHooks.beforeTcpConnect(fd, address, port);344}345}346try {347acquireFD();348try {349socketConnect(address, port, timeout);350/* socket may have been closed during poll/select */351synchronized (fdLock) {352if (closePending) {353throw new SocketException ("Socket closed");354}355}356// If we have a ref. to the Socket, then sets the flags357// created, bound & connected to true.358// This is normally done in Socket.connect() but some359// subclasses of Socket may call impl.connect() directly!360if (socket != null) {361socket.setBound();362socket.setConnected();363}364} finally {365releaseFD();366}367} catch (IOException e) {368close();369throw e;370}371}372373/**374* Binds the socket to the specified address of the specified local port.375* @param address the address376* @param lport the port377*/378protected synchronized void bind(InetAddress address, int lport)379throws IOException380{381synchronized (fdLock) {382if (!closePending && (socket == null || !socket.isBound())) {383NetHooks.beforeTcpBind(fd, address, lport);384}385}386socketBind(address, lport);387if (socket != null)388socket.setBound();389if (serverSocket != null)390serverSocket.setBound();391}392393/**394* Listens, for a specified amount of time, for connections.395* @param count the amount of time to listen for connections396*/397protected synchronized void listen(int count) throws IOException {398socketListen(count);399}400401/**402* Accepts connections.403* @param s the connection404*/405protected void accept(SocketImpl s) throws IOException {406acquireFD();407try {408socketAccept(s);409} finally {410releaseFD();411}412}413414/**415* Gets an InputStream for this socket.416*/417protected synchronized InputStream getInputStream() throws IOException {418synchronized (fdLock) {419if (isClosedOrPending())420throw new IOException("Socket Closed");421if (shut_rd)422throw new IOException("Socket input is shutdown");423if (socketInputStream == null)424socketInputStream = new SocketInputStream(this);425}426return socketInputStream;427}428429void setInputStream(SocketInputStream in) {430socketInputStream = in;431}432433/**434* Gets an OutputStream for this socket.435*/436protected synchronized OutputStream getOutputStream() throws IOException {437synchronized (fdLock) {438if (isClosedOrPending())439throw new IOException("Socket Closed");440if (shut_wr)441throw new IOException("Socket output is shutdown");442if (socketOutputStream == null)443socketOutputStream = new SocketOutputStream(this);444}445return socketOutputStream;446}447448void setFileDescriptor(FileDescriptor fd) {449this.fd = fd;450}451452void setAddress(InetAddress address) {453this.address = address;454}455456void setPort(int port) {457this.port = port;458}459460void setLocalPort(int localport) {461this.localport = localport;462}463464/**465* Returns the number of bytes that can be read without blocking.466*/467protected synchronized int available() throws IOException {468if (isClosedOrPending()) {469throw new IOException("Stream closed.");470}471472/*473* If connection has been reset or shut down for input, then return 0474* to indicate there are no buffered bytes.475*/476if (isConnectionReset() || shut_rd) {477return 0;478}479480/*481* If no bytes available and we were previously notified482* of a connection reset then we move to the reset state.483*484* If are notified of a connection reset then check485* again if there are bytes buffered on the socket.486*/487int n = 0;488try {489n = socketAvailable();490if (n == 0 && isConnectionResetPending()) {491setConnectionReset();492}493} catch (ConnectionResetException exc1) {494setConnectionResetPending();495try {496n = socketAvailable();497if (n == 0) {498setConnectionReset();499}500} catch (ConnectionResetException exc2) {501}502}503return n;504}505506/**507* Closes the socket.508*/509protected void close() throws IOException {510synchronized(fdLock) {511if (fd != null) {512if (!stream) {513ResourceManager.afterUdpClose();514}515if (fdUseCount == 0) {516if (closePending) {517return;518}519closePending = true;520/*521* We close the FileDescriptor in two-steps - first the522* "pre-close" which closes the socket but doesn't523* release the underlying file descriptor. This operation524* may be lengthy due to untransmitted data and a long525* linger interval. Once the pre-close is done we do the526* actual socket to release the fd.527*/528try {529socketPreClose();530} finally {531socketClose();532}533fd = null;534return;535} else {536/*537* If a thread has acquired the fd and a close538* isn't pending then use a deferred close.539* Also decrement fdUseCount to signal the last540* thread that releases the fd to close it.541*/542if (!closePending) {543closePending = true;544fdUseCount--;545socketPreClose();546}547}548}549}550}551552void reset() throws IOException {553if (fd != null) {554socketClose();555}556fd = null;557super.reset();558}559560561/**562* Shutdown read-half of the socket connection;563*/564protected void shutdownInput() throws IOException {565if (fd != null) {566socketShutdown(SHUT_RD);567if (socketInputStream != null) {568socketInputStream.setEOF(true);569}570shut_rd = true;571}572}573574/**575* Shutdown write-half of the socket connection;576*/577protected void shutdownOutput() throws IOException {578if (fd != null) {579socketShutdown(SHUT_WR);580shut_wr = true;581}582}583584protected boolean supportsUrgentData () {585return true;586}587588protected void sendUrgentData (int data) throws IOException {589if (fd == null) {590throw new IOException("Socket Closed");591}592socketSendUrgentData (data);593}594595/**596* Cleans up if the user forgets to close it.597*/598protected void finalize() throws IOException {599close();600}601602/*603* "Acquires" and returns the FileDescriptor for this impl604*605* A corresponding releaseFD is required to "release" the606* FileDescriptor.607*/608FileDescriptor acquireFD() {609synchronized (fdLock) {610fdUseCount++;611return fd;612}613}614615/*616* "Release" the FileDescriptor for this impl.617*618* If the use count goes to -1 then the socket is closed.619*/620void releaseFD() {621synchronized (fdLock) {622fdUseCount--;623if (fdUseCount == -1) {624if (fd != null) {625try {626socketClose();627} catch (IOException e) {628} finally {629fd = null;630}631}632}633}634}635636public boolean isConnectionReset() {637synchronized (resetLock) {638return (resetState == CONNECTION_RESET);639}640}641642public boolean isConnectionResetPending() {643synchronized (resetLock) {644return (resetState == CONNECTION_RESET_PENDING);645}646}647648public void setConnectionReset() {649synchronized (resetLock) {650resetState = CONNECTION_RESET;651}652}653654public void setConnectionResetPending() {655synchronized (resetLock) {656if (resetState == CONNECTION_NOT_RESET) {657resetState = CONNECTION_RESET_PENDING;658}659}660661}662663/*664* Return true if already closed or close is pending665*/666public boolean isClosedOrPending() {667/*668* Lock on fdLock to ensure that we wait if a669* close is in progress.670*/671synchronized (fdLock) {672if (closePending || (fd == null)) {673return true;674} else {675return false;676}677}678}679680/*681* Return the current value of SO_TIMEOUT682*/683public int getTimeout() {684return timeout;685}686687/*688* "Pre-close" a socket by dup'ing the file descriptor - this enables689* the socket to be closed without releasing the file descriptor.690*/691private void socketPreClose() throws IOException {692socketClose0(true);693}694695/*696* Close the socket (and release the file descriptor).697*/698protected void socketClose() throws IOException {699socketClose0(false);700}701702abstract void socketCreate(boolean isServer) throws IOException;703abstract void socketConnect(InetAddress address, int port, int timeout)704throws IOException;705abstract void socketBind(InetAddress address, int port)706throws IOException;707abstract void socketListen(int count)708throws IOException;709abstract void socketAccept(SocketImpl s)710throws IOException;711abstract int socketAvailable()712throws IOException;713abstract void socketClose0(boolean useDeferredClose)714throws IOException;715abstract void socketShutdown(int howto)716throws IOException;717abstract void socketSetOption(int cmd, boolean on, Object value)718throws SocketException;719abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;720abstract void socketSendUrgentData(int data)721throws IOException;722723public final static int SHUT_RD = 0;724public final static int SHUT_WR = 1;725}726727728