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