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