Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net;
     18 
     19 import java.io.IOException;
     20 import java.io.OutputStream;
     21 import java.io.InputStream;
     22 import java.io.FileDescriptor;
     23 import java.net.SocketOptions;
     24 
     25 import android.system.ErrnoException;
     26 import android.system.Os;
     27 import android.system.OsConstants;
     28 
     29 /**
     30  * Socket implementation used for android.net.LocalSocket and
     31  * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
     32  */
     33 class LocalSocketImpl
     34 {
     35     private SocketInputStream fis;
     36     private SocketOutputStream fos;
     37     private Object readMonitor = new Object();
     38     private Object writeMonitor = new Object();
     39 
     40     /** null if closed or not yet created */
     41     private FileDescriptor fd;
     42     /** whether fd is created internally */
     43     private boolean mFdCreatedInternally;
     44 
     45     // These fields are accessed by native code;
     46     /** file descriptor array received during a previous read */
     47     FileDescriptor[] inboundFileDescriptors;
     48     /** file descriptor array that should be written during next write */
     49     FileDescriptor[] outboundFileDescriptors;
     50 
     51     /**
     52      * An input stream for local sockets. Needed because we may
     53      * need to read ancillary data.
     54      */
     55     class SocketInputStream extends InputStream {
     56         /** {@inheritDoc} */
     57         @Override
     58         public int available() throws IOException {
     59             FileDescriptor myFd = fd;
     60             if (myFd == null) throw new IOException("socket closed");
     61 
     62             return available_native(myFd);
     63         }
     64 
     65         /** {@inheritDoc} */
     66         @Override
     67         public void close() throws IOException {
     68             LocalSocketImpl.this.close();
     69         }
     70 
     71         /** {@inheritDoc} */
     72         @Override
     73         public int read() throws IOException {
     74             int ret;
     75             synchronized (readMonitor) {
     76                 FileDescriptor myFd = fd;
     77                 if (myFd == null) throw new IOException("socket closed");
     78 
     79                 ret = read_native(myFd);
     80                 return ret;
     81             }
     82         }
     83 
     84         /** {@inheritDoc} */
     85         @Override
     86         public int read(byte[] b) throws IOException {
     87             return read(b, 0, b.length);
     88         }
     89 
     90         /** {@inheritDoc} */
     91         @Override
     92         public int read(byte[] b, int off, int len) throws IOException {
     93             synchronized (readMonitor) {
     94                 FileDescriptor myFd = fd;
     95                 if (myFd == null) throw new IOException("socket closed");
     96 
     97                 if (off < 0 || len < 0 || (off + len) > b.length ) {
     98                     throw new ArrayIndexOutOfBoundsException();
     99                 }
    100 
    101                 int ret = readba_native(b, off, len, myFd);
    102 
    103                 return ret;
    104             }
    105         }
    106     }
    107 
    108     /**
    109      * An output stream for local sockets. Needed because we may
    110      * need to read ancillary data.
    111      */
    112     class SocketOutputStream extends OutputStream {
    113         /** {@inheritDoc} */
    114         @Override
    115         public void close() throws IOException {
    116             LocalSocketImpl.this.close();
    117         }
    118 
    119         /** {@inheritDoc} */
    120         @Override
    121         public void write (byte[] b) throws IOException {
    122             write(b, 0, b.length);
    123         }
    124 
    125         /** {@inheritDoc} */
    126         @Override
    127         public void write (byte[] b, int off, int len) throws IOException {
    128             synchronized (writeMonitor) {
    129                 FileDescriptor myFd = fd;
    130                 if (myFd == null) throw new IOException("socket closed");
    131 
    132                 if (off < 0 || len < 0 || (off + len) > b.length ) {
    133                     throw new ArrayIndexOutOfBoundsException();
    134                 }
    135                 writeba_native(b, off, len, myFd);
    136             }
    137         }
    138 
    139         /** {@inheritDoc} */
    140         @Override
    141         public void write (int b) throws IOException {
    142             synchronized (writeMonitor) {
    143                 FileDescriptor myFd = fd;
    144                 if (myFd == null) throw new IOException("socket closed");
    145                 write_native(b, myFd);
    146             }
    147         }
    148 
    149         /**
    150          * Wait until the data in sending queue is emptied. A polling version
    151          * for flush implementation.
    152          * @throws IOException
    153          *             if an i/o error occurs.
    154          */
    155         @Override
    156         public void flush() throws IOException {
    157             FileDescriptor myFd = fd;
    158             if (myFd == null) throw new IOException("socket closed");
    159             while(pending_native(myFd) > 0) {
    160                 try {
    161                     Thread.sleep(10);
    162                 } catch (InterruptedException ie) {
    163                     return;
    164                 }
    165             }
    166         }
    167     }
    168 
    169     private native int pending_native(FileDescriptor fd) throws IOException;
    170     private native int available_native(FileDescriptor fd) throws IOException;
    171     private native int read_native(FileDescriptor fd) throws IOException;
    172     private native int readba_native(byte[] b, int off, int len,
    173             FileDescriptor fd) throws IOException;
    174     private native void writeba_native(byte[] b, int off, int len,
    175             FileDescriptor fd) throws IOException;
    176     private native void write_native(int b, FileDescriptor fd)
    177             throws IOException;
    178     private native void connectLocal(FileDescriptor fd, String name,
    179             int namespace) throws IOException;
    180     private native void bindLocal(FileDescriptor fd, String name, int namespace)
    181             throws IOException;
    182     private native void listen_native(FileDescriptor fd, int backlog)
    183             throws IOException;
    184     private native void shutdown(FileDescriptor fd, boolean shutdownInput);
    185     private native Credentials getPeerCredentials_native(
    186             FileDescriptor fd) throws IOException;
    187     private native int getOption_native(FileDescriptor fd, int optID)
    188             throws IOException;
    189     private native void setOption_native(FileDescriptor fd, int optID,
    190             int b, int value) throws IOException;
    191 
    192 //    private native LocalSocketAddress getSockName_native
    193 //            (FileDescriptor fd) throws IOException;
    194 
    195     /**
    196      * Accepts a connection on a server socket.
    197      *
    198      * @param fd file descriptor of server socket
    199      * @param s socket implementation that will become the new socket
    200      * @return file descriptor of new socket
    201      */
    202     private native FileDescriptor accept
    203             (FileDescriptor fd, LocalSocketImpl s) throws IOException;
    204 
    205     /**
    206      * Create a new instance.
    207      */
    208     /*package*/ LocalSocketImpl()
    209     {
    210     }
    211 
    212     /**
    213      * Create a new instance from a file descriptor representing
    214      * a bound socket. The state of the file descriptor is not checked here
    215      *  but the caller can verify socket state by calling listen().
    216      *
    217      * @param fd non-null; bound file descriptor
    218      */
    219     /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
    220     {
    221         this.fd = fd;
    222     }
    223 
    224     public String toString() {
    225         return super.toString() + " fd:" + fd;
    226     }
    227 
    228     /**
    229      * Creates a socket in the underlying OS.
    230      *
    231      * @param sockType either {@link LocalSocket#SOCKET_DGRAM}, {@link LocalSocket#SOCKET_STREAM}
    232      * or {@link LocalSocket#SOCKET_SEQPACKET}
    233      * @throws IOException
    234      */
    235     public void create (int sockType) throws IOException {
    236         // no error if socket already created
    237         // need this for LocalServerSocket.accept()
    238         if (fd == null) {
    239             int osType;
    240             switch (sockType) {
    241                 case LocalSocket.SOCKET_DGRAM:
    242                     osType = OsConstants.SOCK_DGRAM;
    243                     break;
    244                 case LocalSocket.SOCKET_STREAM:
    245                     osType = OsConstants.SOCK_STREAM;
    246                     break;
    247                 case LocalSocket.SOCKET_SEQPACKET:
    248                     osType = OsConstants.SOCK_SEQPACKET;
    249                     break;
    250                 default:
    251                     throw new IllegalStateException("unknown sockType");
    252             }
    253             try {
    254                 fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
    255                 mFdCreatedInternally = true;
    256             } catch (ErrnoException e) {
    257                 e.rethrowAsIOException();
    258             }
    259         }
    260     }
    261 
    262     /**
    263      * Closes the socket.
    264      *
    265      * @throws IOException
    266      */
    267     public void close() throws IOException {
    268         synchronized (LocalSocketImpl.this) {
    269             if ((fd == null) || (mFdCreatedInternally == false)) {
    270                 fd = null;
    271                 return;
    272             }
    273             try {
    274                 Os.close(fd);
    275             } catch (ErrnoException e) {
    276                 e.rethrowAsIOException();
    277             }
    278             fd = null;
    279         }
    280     }
    281 
    282     /** note timeout presently ignored */
    283     protected void connect(LocalSocketAddress address, int timeout)
    284                         throws IOException
    285     {
    286         if (fd == null) {
    287             throw new IOException("socket not created");
    288         }
    289 
    290         connectLocal(fd, address.getName(), address.getNamespace().getId());
    291     }
    292 
    293     /**
    294      * Binds this socket to an endpoint name. May only be called on an instance
    295      * that has not yet been bound.
    296      *
    297      * @param endpoint endpoint address
    298      * @throws IOException
    299      */
    300     public void bind(LocalSocketAddress endpoint) throws IOException
    301     {
    302         if (fd == null) {
    303             throw new IOException("socket not created");
    304         }
    305 
    306         bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId());
    307     }
    308 
    309     protected void listen(int backlog) throws IOException
    310     {
    311         if (fd == null) {
    312             throw new IOException("socket not created");
    313         }
    314 
    315         listen_native(fd, backlog);
    316     }
    317 
    318     /**
    319      * Accepts a new connection to the socket. Blocks until a new
    320      * connection arrives.
    321      *
    322      * @param s a socket that will be used to represent the new connection.
    323      * @throws IOException
    324      */
    325     protected void accept(LocalSocketImpl s) throws IOException
    326     {
    327         if (fd == null) {
    328             throw new IOException("socket not created");
    329         }
    330 
    331         s.fd = accept(fd, s);
    332         s.mFdCreatedInternally = true;
    333     }
    334 
    335     /**
    336      * Retrieves the input stream for this instance.
    337      *
    338      * @return input stream
    339      * @throws IOException if socket has been closed or cannot be created.
    340      */
    341     protected InputStream getInputStream() throws IOException
    342     {
    343         if (fd == null) {
    344             throw new IOException("socket not created");
    345         }
    346 
    347         synchronized (this) {
    348             if (fis == null) {
    349                 fis = new SocketInputStream();
    350             }
    351 
    352             return fis;
    353         }
    354     }
    355 
    356     /**
    357      * Retrieves the output stream for this instance.
    358      *
    359      * @return output stream
    360      * @throws IOException if socket has been closed or cannot be created.
    361      */
    362     protected OutputStream getOutputStream() throws IOException
    363     {
    364         if (fd == null) {
    365             throw new IOException("socket not created");
    366         }
    367 
    368         synchronized (this) {
    369             if (fos == null) {
    370                 fos = new SocketOutputStream();
    371             }
    372 
    373             return fos;
    374         }
    375     }
    376 
    377     /**
    378      * Returns the number of bytes available for reading without blocking.
    379      *
    380      * @return >= 0 count bytes available
    381      * @throws IOException
    382      */
    383     protected int available() throws IOException
    384     {
    385         return getInputStream().available();
    386     }
    387 
    388     /**
    389      * Shuts down the input side of the socket.
    390      *
    391      * @throws IOException
    392      */
    393     protected void shutdownInput() throws IOException
    394     {
    395         if (fd == null) {
    396             throw new IOException("socket not created");
    397         }
    398 
    399         shutdown(fd, true);
    400     }
    401 
    402     /**
    403      * Shuts down the output side of the socket.
    404      *
    405      * @throws IOException
    406      */
    407     protected void shutdownOutput() throws IOException
    408     {
    409         if (fd == null) {
    410             throw new IOException("socket not created");
    411         }
    412 
    413         shutdown(fd, false);
    414     }
    415 
    416     protected FileDescriptor getFileDescriptor()
    417     {
    418         return fd;
    419     }
    420 
    421     protected boolean supportsUrgentData()
    422     {
    423         return false;
    424     }
    425 
    426     protected void sendUrgentData(int data) throws IOException
    427     {
    428         throw new RuntimeException ("not impled");
    429     }
    430 
    431     public Object getOption(int optID) throws IOException
    432     {
    433         if (fd == null) {
    434             throw new IOException("socket not created");
    435         }
    436 
    437         if (optID == SocketOptions.SO_TIMEOUT) {
    438             return 0;
    439         }
    440 
    441         int value = getOption_native(fd, optID);
    442         switch (optID)
    443         {
    444             case SocketOptions.SO_RCVBUF:
    445             case SocketOptions.SO_SNDBUF:
    446                 return value;
    447             case SocketOptions.SO_REUSEADDR:
    448             default:
    449                 return value;
    450         }
    451     }
    452 
    453     public void setOption(int optID, Object value)
    454             throws IOException {
    455         /*
    456          * Boolean.FALSE is used to disable some options, so it
    457          * is important to distinguish between FALSE and unset.
    458          * We define it here that -1 is unset, 0 is FALSE, and 1
    459          * is TRUE.
    460          */
    461         int boolValue = -1;
    462         int intValue = 0;
    463 
    464         if (fd == null) {
    465             throw new IOException("socket not created");
    466         }
    467 
    468         if (value instanceof Integer) {
    469             intValue = (Integer)value;
    470         } else if (value instanceof Boolean) {
    471             boolValue = ((Boolean) value)? 1 : 0;
    472         } else {
    473             throw new IOException("bad value: " + value);
    474         }
    475 
    476         setOption_native(fd, optID, boolValue, intValue);
    477     }
    478 
    479     /**
    480      * Enqueues a set of file descriptors to send to the peer. The queue
    481      * is one deep. The file descriptors will be sent with the next write
    482      * of normal data, and will be delivered in a single ancillary message.
    483      * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
    484      *
    485      * @param fds non-null; file descriptors to send.
    486      * @throws IOException
    487      */
    488     public void setFileDescriptorsForSend(FileDescriptor[] fds) {
    489         synchronized(writeMonitor) {
    490             outboundFileDescriptors = fds;
    491         }
    492     }
    493 
    494     /**
    495      * Retrieves a set of file descriptors that a peer has sent through
    496      * an ancillary message. This method retrieves the most recent set sent,
    497      * and then returns null until a new set arrives.
    498      * File descriptors may only be passed along with regular data, so this
    499      * method can only return a non-null after a read operation.
    500      *
    501      * @return null or file descriptor array
    502      * @throws IOException
    503      */
    504     public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
    505         synchronized(readMonitor) {
    506             FileDescriptor[] result = inboundFileDescriptors;
    507 
    508             inboundFileDescriptors = null;
    509             return result;
    510         }
    511     }
    512 
    513     /**
    514      * Retrieves the credentials of this socket's peer. Only valid on
    515      * connected sockets.
    516      *
    517      * @return non-null; peer credentials
    518      * @throws IOException
    519      */
    520     public Credentials getPeerCredentials() throws IOException
    521     {
    522         return getPeerCredentials_native(fd);
    523     }
    524 
    525     /**
    526      * Retrieves the socket name from the OS.
    527      *
    528      * @return non-null; socket name
    529      * @throws IOException on failure
    530      */
    531     public LocalSocketAddress getSockAddress() throws IOException
    532     {
    533         return null;
    534         //TODO implement this
    535         //return getSockName_native(fd);
    536     }
    537 
    538     @Override
    539     protected void finalize() throws IOException {
    540         close();
    541     }
    542 }
    543