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