Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.net;
     28 
     29 import java.io.IOException;
     30 import java.io.InputStream;
     31 import java.io.OutputStream;
     32 import java.io.FileDescriptor;
     33 
     34 import dalvik.system.BlockGuard;
     35 import dalvik.system.CloseGuard;
     36 import dalvik.system.SocketTagger;
     37 import sun.net.ConnectionResetException;
     38 import sun.net.NetHooks;
     39 import sun.net.ResourceManager;
     40 
     41 /**
     42  * Default Socket Implementation. This implementation does
     43  * not implement any security checks.
     44  * Note this class should <b>NOT</b> be public.
     45  *
     46  * @author  Steven B. Byrne
     47  */
     48 abstract class AbstractPlainSocketImpl extends SocketImpl
     49 {
     50     /* instance variable for SO_TIMEOUT */
     51     int timeout;   // timeout in millisec
     52     // Android-removed: traffic class is set through socket
     53     // private int trafficClass;
     54 
     55     private boolean shut_rd = false;
     56     private boolean shut_wr = false;
     57 
     58     private SocketInputStream socketInputStream = null;
     59     private SocketOutputStream socketOutputStream = null;
     60 
     61     /* number of threads using the FileDescriptor */
     62     protected int fdUseCount = 0;
     63 
     64     /* lock when increment/decrementing fdUseCount */
     65     protected final Object fdLock = new Object();
     66 
     67     /* indicates a close is pending on the file descriptor */
     68     protected boolean closePending = false;
     69 
     70     /* indicates connection reset state */
     71     private int CONNECTION_NOT_RESET = 0;
     72     private int CONNECTION_RESET_PENDING = 1;
     73     private int CONNECTION_RESET = 2;
     74     private int resetState;
     75     private final Object resetLock = new Object();
     76 
     77    /* whether this Socket is a stream (TCP) socket or not (UDP)
     78     */
     79     protected boolean stream;
     80 
     81     private final CloseGuard guard = CloseGuard.get();
     82 
     83     /**
     84      * Creates a socket with a boolean that specifies whether this
     85      * is a stream socket (true) or an unconnected UDP socket (false).
     86      */
     87     protected synchronized void create(boolean stream) throws IOException {
     88         this.stream = stream;
     89         if (!stream) {
     90             ResourceManager.beforeUdpCreate();
     91             try {
     92                 socketCreate(false);
     93             } catch (IOException ioe) {
     94                 ResourceManager.afterUdpClose();
     95                 throw ioe;
     96             }
     97         } else {
     98             socketCreate(true);
     99         }
    100         if (socket != null)
    101             socket.setCreated();
    102         if (serverSocket != null)
    103             serverSocket.setCreated();
    104 
    105         // socketCreate will set |fd| if it succeeds.
    106         if (fd != null && fd.valid()) {
    107             guard.open("close");
    108         }
    109     }
    110 
    111     /**
    112      * Creates a socket and connects it to the specified port on
    113      * the specified host.
    114      * @param host the specified host
    115      * @param port the specified port
    116      */
    117     protected void connect(String host, int port)
    118         throws UnknownHostException, IOException
    119     {
    120         boolean connected = false;
    121         try {
    122             InetAddress address = InetAddress.getByName(host);
    123             this.port = port;
    124             this.address = address;
    125 
    126             connectToAddress(address, port, timeout);
    127             connected = true;
    128         } finally {
    129             if (!connected) {
    130                 try {
    131                     close();
    132                 } catch (IOException ioe) {
    133                     /* Do nothing. If connect threw an exception then
    134                        it will be passed up the call stack */
    135                 }
    136             }
    137         }
    138     }
    139 
    140     /**
    141      * Creates a socket and connects it to the specified address on
    142      * the specified port.
    143      * @param address the address
    144      * @param port the specified port
    145      */
    146     protected void connect(InetAddress address, int port) throws IOException {
    147         this.port = port;
    148         this.address = address;
    149 
    150         try {
    151             connectToAddress(address, port, timeout);
    152             return;
    153         } catch (IOException e) {
    154             // everything failed
    155             close();
    156             throw e;
    157         }
    158     }
    159 
    160     /**
    161      * Creates a socket and connects it to the specified address on
    162      * the specified port.
    163      * @param address the address
    164      * @param timeout the timeout value in milliseconds, or zero for no timeout.
    165      * @throws IOException if connection fails
    166      * @throws  IllegalArgumentException if address is null or is a
    167      *          SocketAddress subclass not supported by this socket
    168      * @since 1.4
    169      */
    170     protected void connect(SocketAddress address, int timeout)
    171             throws IOException {
    172         boolean connected = false;
    173         try {
    174             if (address == null || !(address instanceof InetSocketAddress))
    175                 throw new IllegalArgumentException("unsupported address type");
    176             InetSocketAddress addr = (InetSocketAddress) address;
    177             if (addr.isUnresolved())
    178                 throw new UnknownHostException(addr.getHostName());
    179             this.port = addr.getPort();
    180             this.address = addr.getAddress();
    181 
    182             connectToAddress(this.address, port, timeout);
    183             connected = true;
    184         } finally {
    185             if (!connected) {
    186                 try {
    187                     close();
    188                 } catch (IOException ioe) {
    189                     /* Do nothing. If connect threw an exception then
    190                        it will be passed up the call stack */
    191                 }
    192             }
    193         }
    194     }
    195 
    196     private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
    197         if (address.isAnyLocalAddress()) {
    198             doConnect(InetAddress.getLocalHost(), port, timeout);
    199         } else {
    200             doConnect(address, port, timeout);
    201         }
    202     }
    203 
    204     public void setOption(int opt, Object val) throws SocketException {
    205         if (isClosedOrPending()) {
    206             throw new SocketException("Socket Closed");
    207         }
    208         // Android-removed: Logic dealing with value type moved to socketSetOption.
    209         /*
    210         boolean on = true;
    211         switch (opt) {
    212             /* check type safety b4 going native.  These should never
    213              * fail, since only java.Socket* has access to
    214              * PlainSocketImpl.setOption().
    215              *
    216         case SO_LINGER:
    217             if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
    218                 throw new SocketException("Bad parameter for option");
    219             if (val instanceof Boolean) {
    220                 /* true only if disabling - enabling should be Integer *
    221                 on = false;
    222             }
    223             break;
    224         case SO_TIMEOUT:
    225             if (val == null || (!(val instanceof Integer)))
    226                 throw new SocketException("Bad parameter for SO_TIMEOUT");
    227             int tmp = ((Integer) val).intValue();
    228             if (tmp < 0)
    229                 throw new IllegalArgumentException("timeout < 0");
    230             timeout = tmp;
    231             break;
    232         case IP_TOS:
    233              if (val == null || !(val instanceof Integer)) {
    234                  throw new SocketException("bad argument for IP_TOS");
    235              }
    236              trafficClass = ((Integer)val).intValue();
    237              break;
    238         case SO_BINDADDR:
    239             throw new SocketException("Cannot re-bind socket");
    240         case TCP_NODELAY:
    241             if (val == null || !(val instanceof Boolean))
    242                 throw new SocketException("bad parameter for TCP_NODELAY");
    243             on = ((Boolean)val).booleanValue();
    244             break;
    245         case SO_SNDBUF:
    246         case SO_RCVBUF:
    247             if (val == null || !(val instanceof Integer) ||
    248                 !(((Integer)val).intValue() > 0)) {
    249                 throw new SocketException("bad parameter for SO_SNDBUF " +
    250                                           "or SO_RCVBUF");
    251             }
    252             break;
    253         case SO_KEEPALIVE:
    254             if (val == null || !(val instanceof Boolean))
    255                 throw new SocketException("bad parameter for SO_KEEPALIVE");
    256             on = ((Boolean)val).booleanValue();
    257             break;
    258         case SO_OOBINLINE:
    259             if (val == null || !(val instanceof Boolean))
    260                 throw new SocketException("bad parameter for SO_OOBINLINE");
    261             on = ((Boolean)val).booleanValue();
    262             break;
    263         case SO_REUSEADDR:
    264             if (val == null || !(val instanceof Boolean))
    265                 throw new SocketException("bad parameter for SO_REUSEADDR");
    266             on = ((Boolean)val).booleanValue();
    267             break;
    268         default:
    269             throw new SocketException("unrecognized TCP option: " + opt);
    270         }
    271         socketSetOption(opt, on, val);
    272         */
    273         if (opt == SO_TIMEOUT) {
    274             timeout = (Integer) val;
    275         }
    276         socketSetOption(opt, val);
    277     }
    278     public Object getOption(int opt) throws SocketException {
    279         if (isClosedOrPending()) {
    280             throw new SocketException("Socket Closed");
    281         }
    282         if (opt == SO_TIMEOUT) {
    283             return new Integer(timeout);
    284         }
    285         // Android-removed: Logic dealing with value type moved to socketGetOption.
    286         /*
    287         int ret = 0;
    288         /*
    289          * The native socketGetOption() knows about 3 options.
    290          * The 32 bit value it returns will be interpreted according
    291          * to what we're asking.  A return of -1 means it understands
    292          * the option but its turned off.  It will raise a SocketException
    293          * if "opt" isn't one it understands.
    294          *
    295 
    296         switch (opt) {
    297         case TCP_NODELAY:
    298             ret = socketGetOption(opt, null);
    299             return Boolean.valueOf(ret != -1);
    300         case SO_OOBINLINE:
    301             ret = socketGetOption(opt, null);
    302             return Boolean.valueOf(ret != -1);
    303         case SO_LINGER:
    304             ret = socketGetOption(opt, null);
    305             return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
    306         case SO_REUSEADDR:
    307             ret = socketGetOption(opt, null);
    308             return Boolean.valueOf(ret != -1);
    309         case SO_BINDADDR:
    310             InetAddressContainer in = new InetAddressContainer();
    311             ret = socketGetOption(opt, in);
    312             return in.addr;
    313         case SO_SNDBUF:
    314         case SO_RCVBUF:
    315             ret = socketGetOption(opt, null);
    316             return new Integer(ret);
    317         case IP_TOS:
    318             try {
    319                 ret = socketGetOption(opt, null);
    320                 if (ret == -1) { // ipv6 tos
    321                     return trafficClass;
    322                 } else {
    323                     return ret;
    324                 }
    325             } catch (SocketException se) {
    326                 // TODO - should make better effort to read TOS or TCLASS
    327                 return trafficClass; // ipv6 tos
    328             }
    329         case SO_KEEPALIVE:
    330             ret = socketGetOption(opt, null);
    331             return Boolean.valueOf(ret != -1);
    332         // should never get here
    333         default:
    334             return null;
    335         }
    336         */
    337         return socketGetOption(opt);
    338     }
    339 
    340     /**
    341      * The workhorse of the connection operation.  Tries several times to
    342      * establish a connection to the given <host, port>.  If unsuccessful,
    343      * throws an IOException indicating what went wrong.
    344      */
    345 
    346     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
    347         synchronized (fdLock) {
    348             if (!closePending && (socket == null || !socket.isBound())) {
    349                 NetHooks.beforeTcpConnect(fd, address, port);
    350             }
    351         }
    352         try {
    353             acquireFD();
    354             try {
    355                 BlockGuard.getThreadPolicy().onNetwork();
    356                 socketConnect(address, port, timeout);
    357                 /* socket may have been closed during poll/select */
    358                 synchronized (fdLock) {
    359                     if (closePending) {
    360                         throw new SocketException ("Socket closed");
    361                     }
    362                 }
    363                 // If we have a ref. to the Socket, then sets the flags
    364                 // created, bound & connected to true.
    365                 // This is normally done in Socket.connect() but some
    366                 // subclasses of Socket may call impl.connect() directly!
    367                 if (socket != null) {
    368                     socket.setBound();
    369                     socket.setConnected();
    370                 }
    371             } finally {
    372                 releaseFD();
    373             }
    374         } catch (IOException e) {
    375             close();
    376             throw e;
    377         }
    378     }
    379 
    380     /**
    381      * Binds the socket to the specified address of the specified local port.
    382      * @param address the address
    383      * @param lport the port
    384      */
    385     protected synchronized void bind(InetAddress address, int lport)
    386         throws IOException
    387     {
    388        synchronized (fdLock) {
    389             if (!closePending && (socket == null || !socket.isBound())) {
    390                 NetHooks.beforeTcpBind(fd, address, lport);
    391             }
    392         }
    393         socketBind(address, lport);
    394         if (socket != null)
    395             socket.setBound();
    396         if (serverSocket != null)
    397             serverSocket.setBound();
    398     }
    399 
    400     /**
    401      * Listens, for a specified amount of time, for connections.
    402      * @param count the amount of time to listen for connections
    403      */
    404     protected synchronized void listen(int count) throws IOException {
    405         socketListen(count);
    406     }
    407 
    408     /**
    409      * Accepts connections.
    410      * @param s the connection
    411      */
    412     protected void accept(SocketImpl s) throws IOException {
    413         acquireFD();
    414         try {
    415             BlockGuard.getThreadPolicy().onNetwork();
    416             socketAccept(s);
    417         } finally {
    418             releaseFD();
    419         }
    420     }
    421 
    422     /**
    423      * Gets an InputStream for this socket.
    424      */
    425     protected synchronized InputStream getInputStream() throws IOException {
    426         synchronized (fdLock) {
    427             if (isClosedOrPending())
    428                 throw new IOException("Socket Closed");
    429             if (shut_rd)
    430                 throw new IOException("Socket input is shutdown");
    431             if (socketInputStream == null)
    432                 socketInputStream = new SocketInputStream(this);
    433         }
    434         return socketInputStream;
    435     }
    436 
    437     void setInputStream(SocketInputStream in) {
    438         socketInputStream = in;
    439     }
    440 
    441     /**
    442      * Gets an OutputStream for this socket.
    443      */
    444     protected synchronized OutputStream getOutputStream() throws IOException {
    445         synchronized (fdLock) {
    446             if (isClosedOrPending())
    447                 throw new IOException("Socket Closed");
    448             if (shut_wr)
    449                 throw new IOException("Socket output is shutdown");
    450             if (socketOutputStream == null)
    451                 socketOutputStream = new SocketOutputStream(this);
    452         }
    453         return socketOutputStream;
    454     }
    455 
    456     void setFileDescriptor(FileDescriptor fd) {
    457         this.fd = fd;
    458     }
    459 
    460     void setAddress(InetAddress address) {
    461         this.address = address;
    462     }
    463 
    464     void setPort(int port) {
    465         this.port = port;
    466     }
    467 
    468     void setLocalPort(int localport) {
    469         this.localport = localport;
    470     }
    471 
    472     /**
    473      * Returns the number of bytes that can be read without blocking.
    474      */
    475     protected synchronized int available() throws IOException {
    476         if (isClosedOrPending()) {
    477             throw new IOException("Stream closed.");
    478         }
    479 
    480         /*
    481          * If connection has been reset then return 0 to indicate
    482          * there are no buffered bytes.
    483          */
    484         if (isConnectionReset()) {
    485             return 0;
    486         }
    487 
    488         /*
    489          * If no bytes available and we were previously notified
    490          * of a connection reset then we move to the reset state.
    491          *
    492          * If are notified of a connection reset then check
    493          * again if there are bytes buffered on the socket.
    494          */
    495         int n = 0;
    496         try {
    497             n = socketAvailable();
    498             if (n == 0 && isConnectionResetPending()) {
    499                 setConnectionReset();
    500             }
    501         } catch (ConnectionResetException exc1) {
    502             setConnectionResetPending();
    503             try {
    504                 n = socketAvailable();
    505                 if (n == 0) {
    506                     setConnectionReset();
    507                 }
    508             } catch (ConnectionResetException exc2) {
    509             }
    510         }
    511         return n;
    512     }
    513 
    514     /**
    515      * Closes the socket.
    516      */
    517     protected void close() throws IOException {
    518         synchronized(fdLock) {
    519             if (fd != null && fd.valid()) {
    520                 if (!stream) {
    521                     ResourceManager.afterUdpClose();
    522                 }
    523                 // Android-changed:
    524                 // Socket should be untagged before the preclose. After preclose,
    525                 // socket will dup2-ed to marker_fd, therefore, it won't describe the same file.
    526                 // If closingPending is true, then the socket has been preclosed.
    527                 //
    528                 // Also, close the CloseGuard when the #close is called.
    529                 if (!closePending) {
    530                     closePending = true;
    531                     SocketTagger.get().untag(fd);
    532                     guard.close();
    533 
    534                     if (fdUseCount == 0) {
    535                         /*
    536                          * We close the FileDescriptor in two-steps - first the
    537                          * "pre-close" which closes the socket but doesn't
    538                          * release the underlying file descriptor. This operation
    539                          * may be lengthy due to untransmitted data and a long
    540                          * linger interval. Once the pre-close is done we do the
    541                          * actual socket to release the fd.
    542                          */
    543                         try {
    544                             socketPreClose();
    545                         } finally {
    546                             socketClose();
    547                         }
    548                         // Android-changed(http://b/26470377): Some Android code doesn't expect file
    549                         // descriptor to be null. socketClose invalidates the fd by closing the fd.
    550                         // fd = null;
    551                         return;
    552                     } else {
    553                         /*
    554                          * If a thread has acquired the fd and a close
    555                          * isn't pending then use a deferred close.
    556                          * Also decrement fdUseCount to signal the last
    557                          * thread that releases the fd to close it.
    558                          */
    559                         fdUseCount--;
    560                         socketPreClose();
    561                     }
    562                 }
    563             }
    564         }
    565     }
    566 
    567     void reset() throws IOException {
    568         if (fd != null && fd.valid()) {
    569             socketClose();
    570             // Android-changed: Notified the CloseGuard object as the fd has been released.
    571             guard.close();
    572         }
    573         super.reset();
    574     }
    575 
    576 
    577     /**
    578      * Shutdown read-half of the socket connection;
    579      */
    580     protected void shutdownInput() throws IOException {
    581       if (fd != null && fd.valid()) {
    582           socketShutdown(SHUT_RD);
    583           if (socketInputStream != null) {
    584               socketInputStream.setEOF(true);
    585           }
    586           shut_rd = true;
    587       }
    588     }
    589 
    590     /**
    591      * Shutdown write-half of the socket connection;
    592      */
    593     protected void shutdownOutput() throws IOException {
    594       if (fd != null && fd.valid()) {
    595           socketShutdown(SHUT_WR);
    596           shut_wr = true;
    597       }
    598     }
    599 
    600     protected boolean supportsUrgentData () {
    601         return true;
    602     }
    603 
    604     protected void sendUrgentData (int data) throws IOException {
    605         if (fd == null || !fd.valid()) {
    606             throw new IOException("Socket Closed");
    607         }
    608         socketSendUrgentData (data);
    609     }
    610 
    611     /**
    612      * Cleans up if the user forgets to close it.
    613      */
    614     protected void finalize() throws IOException {
    615         if (guard != null) {
    616             guard.warnIfOpen();
    617         }
    618 
    619         close();
    620     }
    621 
    622     /*
    623      * "Acquires" and returns the FileDescriptor for this impl
    624      *
    625      * A corresponding releaseFD is required to "release" the
    626      * FileDescriptor.
    627      */
    628     FileDescriptor acquireFD() {
    629         synchronized (fdLock) {
    630             fdUseCount++;
    631             return fd;
    632         }
    633     }
    634 
    635     /*
    636      * "Release" the FileDescriptor for this impl.
    637      *
    638      * If the use count goes to -1 then the socket is closed.
    639      */
    640     void releaseFD() {
    641         synchronized (fdLock) {
    642             fdUseCount--;
    643             if (fdUseCount == -1) {
    644                 if (fd != null) {
    645                     try {
    646                         socketClose();
    647                     } catch (IOException e) {
    648                         // Android-changed(http://b/26470377): Some Android code doesn't expect file
    649                         // descriptor to be null. socketClose invalidates the fd by closing the fd.
    650                         // } finally {
    651                         //     fd = null;
    652                     }
    653                 }
    654             }
    655         }
    656     }
    657 
    658     public boolean isConnectionReset() {
    659         synchronized (resetLock) {
    660             return (resetState == CONNECTION_RESET);
    661         }
    662     }
    663 
    664     public boolean isConnectionResetPending() {
    665         synchronized (resetLock) {
    666             return (resetState == CONNECTION_RESET_PENDING);
    667         }
    668     }
    669 
    670     public void setConnectionReset() {
    671         synchronized (resetLock) {
    672             resetState = CONNECTION_RESET;
    673         }
    674     }
    675 
    676     public void setConnectionResetPending() {
    677         synchronized (resetLock) {
    678             if (resetState == CONNECTION_NOT_RESET) {
    679                 resetState = CONNECTION_RESET_PENDING;
    680             }
    681         }
    682 
    683     }
    684 
    685     /*
    686      * Return true if already closed or close is pending
    687      */
    688     public boolean isClosedOrPending() {
    689         /*
    690          * Lock on fdLock to ensure that we wait if a
    691          * close is in progress.
    692          */
    693         synchronized (fdLock) {
    694             if (closePending || (fd == null) || !fd.valid()) {
    695                 return true;
    696             } else {
    697                 return false;
    698             }
    699         }
    700     }
    701 
    702     /*
    703      * Return the current value of SO_TIMEOUT
    704      */
    705     public int getTimeout() {
    706         return timeout;
    707     }
    708 
    709     /*
    710      * "Pre-close" a socket by dup'ing the file descriptor - this enables
    711      * the socket to be closed without releasing the file descriptor.
    712      */
    713     private void socketPreClose() throws IOException {
    714         socketClose0(true);
    715     }
    716 
    717     /*
    718      * Close the socket (and release the file descriptor).
    719      */
    720     protected void socketClose() throws IOException {
    721         socketClose0(false);
    722     }
    723 
    724     abstract void socketCreate(boolean isServer) throws IOException;
    725     abstract void socketConnect(InetAddress address, int port, int timeout)
    726         throws IOException;
    727     abstract void socketBind(InetAddress address, int port)
    728         throws IOException;
    729     abstract void socketListen(int count)
    730         throws IOException;
    731     abstract void socketAccept(SocketImpl s)
    732         throws IOException;
    733     abstract int socketAvailable()
    734         throws IOException;
    735     abstract void socketClose0(boolean useDeferredClose)
    736         throws IOException;
    737     abstract void socketShutdown(int howto)
    738         throws IOException;
    739 
    740     // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object
    741     // values.
    742     abstract void socketSetOption(int cmd, Object value) throws SocketException;
    743     abstract Object socketGetOption(int opt) throws SocketException;
    744 
    745     abstract void socketSendUrgentData(int data)
    746         throws IOException;
    747 
    748     public final static int SHUT_RD = 0;
    749     public final static int SHUT_WR = 1;
    750 }
    751