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 android.annotation.UnsupportedAppUsage;
     20 import java.io.Closeable;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.net.SocketOptions;
     26 
     27 /**
     28  * Creates a (non-server) socket in the UNIX-domain namespace. The interface
     29  * here is not entirely unlike that of java.net.Socket. This class and the streams
     30  * returned from it may be used from multiple threads.
     31  */
     32 public class LocalSocket implements Closeable {
     33 
     34     @UnsupportedAppUsage
     35     private final LocalSocketImpl impl;
     36     /** false if impl.create() needs to be called */
     37     private volatile boolean implCreated;
     38     private LocalSocketAddress localAddress;
     39     private boolean isBound;
     40     private boolean isConnected;
     41     private final int sockType;
     42 
     43     /** unknown socket type (used for constructor with existing file descriptor) */
     44     /* package */ static final int SOCKET_UNKNOWN = 0;
     45     /** Datagram socket type */
     46     public static final int SOCKET_DGRAM = 1;
     47     /** Stream socket type */
     48     public static final int SOCKET_STREAM = 2;
     49     /** Sequential packet socket type */
     50     public static final int SOCKET_SEQPACKET = 3;
     51 
     52     /**
     53      * Creates a AF_LOCAL/UNIX domain stream socket.
     54      */
     55     public LocalSocket() {
     56         this(SOCKET_STREAM);
     57     }
     58 
     59     /**
     60      * Creates a AF_LOCAL/UNIX domain stream socket with given socket type
     61      *
     62      * @param sockType either {@link #SOCKET_DGRAM}, {@link #SOCKET_STREAM}
     63      * or {@link #SOCKET_SEQPACKET}
     64      */
     65     public LocalSocket(int sockType) {
     66         this(new LocalSocketImpl(), sockType);
     67     }
     68 
     69     private LocalSocket(LocalSocketImpl impl, int sockType) {
     70         this.impl = impl;
     71         this.sockType = sockType;
     72         this.isConnected = false;
     73         this.isBound = false;
     74     }
     75 
     76     /**
     77      * Creates a LocalSocket instances using the FileDescriptor for an already-connected
     78      * AF_LOCAL/UNIX domain stream socket. Note: the FileDescriptor must be closed by the caller:
     79      * closing the LocalSocket will not close it.
     80      *
     81      * @hide - used by BluetoothSocket.
     82      */
     83     public static LocalSocket createConnectedLocalSocket(FileDescriptor fd) {
     84         return createConnectedLocalSocket(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
     85     }
     86 
     87     /**
     88      * for use with LocalServerSocket.accept()
     89      */
     90     static LocalSocket createLocalSocketForAccept(LocalSocketImpl impl) {
     91         return createConnectedLocalSocket(impl, SOCKET_UNKNOWN);
     92     }
     93 
     94     /**
     95      * Creates a LocalSocket from an existing LocalSocketImpl that is already connected.
     96      */
     97     private static LocalSocket createConnectedLocalSocket(LocalSocketImpl impl, int sockType) {
     98         LocalSocket socket = new LocalSocket(impl, sockType);
     99         socket.isConnected = true;
    100         socket.isBound = true;
    101         socket.implCreated = true;
    102         return socket;
    103     }
    104 
    105     /** {@inheritDoc} */
    106     @Override
    107     public String toString() {
    108         return super.toString() + " impl:" + impl;
    109     }
    110 
    111     /**
    112      * It's difficult to discern from the spec when impl.create() should be
    113      * called, but it seems like a reasonable rule is "as soon as possible,
    114      * but not in a context where IOException cannot be thrown"
    115      *
    116      * @throws IOException from SocketImpl.create()
    117      */
    118     private void implCreateIfNeeded() throws IOException {
    119         if (!implCreated) {
    120             synchronized (this) {
    121                 if (!implCreated) {
    122                     try {
    123                         impl.create(sockType);
    124                     } finally {
    125                         implCreated = true;
    126                     }
    127                 }
    128             }
    129         }
    130     }
    131 
    132     /**
    133      * Connects this socket to an endpoint. May only be called on an instance
    134      * that has not yet been connected.
    135      *
    136      * @param endpoint endpoint address
    137      * @throws IOException if socket is in invalid state or the address does
    138      * not exist.
    139      */
    140     public void connect(LocalSocketAddress endpoint) throws IOException {
    141         synchronized (this) {
    142             if (isConnected) {
    143                 throw new IOException("already connected");
    144             }
    145 
    146             implCreateIfNeeded();
    147             impl.connect(endpoint, 0);
    148             isConnected = true;
    149             isBound = true;
    150         }
    151     }
    152 
    153     /**
    154      * Binds this socket to an endpoint name. May only be called on an instance
    155      * that has not yet been bound.
    156      *
    157      * @param bindpoint endpoint address
    158      * @throws IOException
    159      */
    160     public void bind(LocalSocketAddress bindpoint) throws IOException {
    161         implCreateIfNeeded();
    162 
    163         synchronized (this) {
    164             if (isBound) {
    165                 throw new IOException("already bound");
    166             }
    167 
    168             localAddress = bindpoint;
    169             impl.bind(localAddress);
    170             isBound = true;
    171         }
    172     }
    173 
    174     /**
    175      * Retrieves the name that this socket is bound to, if any.
    176      *
    177      * @return Local address or null if anonymous
    178      */
    179     public LocalSocketAddress getLocalSocketAddress() {
    180         return localAddress;
    181     }
    182 
    183     /**
    184      * Retrieves the input stream for this instance.
    185      *
    186      * @return input stream
    187      * @throws IOException if socket has been closed or cannot be created.
    188      */
    189     public InputStream getInputStream() throws IOException {
    190         implCreateIfNeeded();
    191         return impl.getInputStream();
    192     }
    193 
    194     /**
    195      * Retrieves the output stream for this instance.
    196      *
    197      * @return output stream
    198      * @throws IOException if socket has been closed or cannot be created.
    199      */
    200     public OutputStream getOutputStream() throws IOException {
    201         implCreateIfNeeded();
    202         return impl.getOutputStream();
    203     }
    204 
    205     /**
    206      * Closes the socket.
    207      *
    208      * @throws IOException
    209      */
    210     @Override
    211     public void close() throws IOException {
    212         implCreateIfNeeded();
    213         impl.close();
    214     }
    215 
    216     /**
    217      * Shuts down the input side of the socket.
    218      *
    219      * @throws IOException
    220      */
    221     public void shutdownInput() throws IOException {
    222         implCreateIfNeeded();
    223         impl.shutdownInput();
    224     }
    225 
    226     /**
    227      * Shuts down the output side of the socket.
    228      *
    229      * @throws IOException
    230      */
    231     public void shutdownOutput() throws IOException {
    232         implCreateIfNeeded();
    233         impl.shutdownOutput();
    234     }
    235 
    236     public void setReceiveBufferSize(int size) throws IOException {
    237         impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
    238     }
    239 
    240     public int getReceiveBufferSize() throws IOException {
    241         return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
    242     }
    243 
    244     public void setSoTimeout(int n) throws IOException {
    245         impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n));
    246     }
    247 
    248     public int getSoTimeout() throws IOException {
    249         return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
    250     }
    251 
    252     public void setSendBufferSize(int n) throws IOException {
    253         impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n));
    254     }
    255 
    256     public int getSendBufferSize() throws IOException {
    257         return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
    258     }
    259 
    260     //???SEC
    261     public LocalSocketAddress getRemoteSocketAddress() {
    262         throw new UnsupportedOperationException();
    263     }
    264 
    265     //???SEC
    266     public synchronized boolean isConnected() {
    267         return isConnected;
    268     }
    269 
    270     //???SEC
    271     public boolean isClosed() {
    272         throw new UnsupportedOperationException();
    273     }
    274 
    275     //???SEC
    276     public synchronized boolean isBound() {
    277         return isBound;
    278     }
    279 
    280     //???SEC
    281     public boolean isOutputShutdown() {
    282         throw new UnsupportedOperationException();
    283     }
    284 
    285     //???SEC
    286     public boolean isInputShutdown() {
    287         throw new UnsupportedOperationException();
    288     }
    289 
    290     //???SEC
    291     public void connect(LocalSocketAddress endpoint, int timeout)
    292             throws IOException {
    293         throw new UnsupportedOperationException();
    294     }
    295 
    296     /**
    297      * Enqueues a set of file descriptors to send to the peer. The queue
    298      * is one deep. The file descriptors will be sent with the next write
    299      * of normal data, and will be delivered in a single ancillary message.
    300      * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
    301      *
    302      * @param fds non-null; file descriptors to send.
    303      */
    304     public void setFileDescriptorsForSend(FileDescriptor[] fds) {
    305         impl.setFileDescriptorsForSend(fds);
    306     }
    307 
    308     /**
    309      * Retrieves a set of file descriptors that a peer has sent through
    310      * an ancillary message. This method retrieves the most recent set sent,
    311      * and then returns null until a new set arrives.
    312      * File descriptors may only be passed along with regular data, so this
    313      * method can only return a non-null after a read operation.
    314      *
    315      * @return null or file descriptor array
    316      * @throws IOException
    317      */
    318     public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
    319         return impl.getAncillaryFileDescriptors();
    320     }
    321 
    322     /**
    323      * Retrieves the credentials of this socket's peer. Only valid on
    324      * connected sockets.
    325      *
    326      * @return non-null; peer credentials
    327      * @throws IOException
    328      */
    329     public Credentials getPeerCredentials() throws IOException {
    330         return impl.getPeerCredentials();
    331     }
    332 
    333     /**
    334      * Returns file descriptor or null if not yet open/already closed
    335      *
    336      * @return fd or null
    337      */
    338     public FileDescriptor getFileDescriptor() {
    339         return impl.getFileDescriptor();
    340     }
    341 }
    342