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