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      */
LocalSocket()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      */
LocalSocket(int sockType)65     public LocalSocket(int sockType) {
66         this(new LocalSocketImpl(), sockType);
67     }
68 
LocalSocket(LocalSocketImpl impl, int sockType)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      */
createConnectedLocalSocket(FileDescriptor fd)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      */
createLocalSocketForAccept(LocalSocketImpl impl)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      */
createConnectedLocalSocket(LocalSocketImpl impl, int sockType)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
toString()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      */
implCreateIfNeeded()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      */
connect(LocalSocketAddress endpoint)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      */
bind(LocalSocketAddress bindpoint)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      */
getLocalSocketAddress()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      */
getInputStream()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      */
getOutputStream()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
close()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      */
shutdownInput()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      */
shutdownOutput()231     public void shutdownOutput() throws IOException {
232         implCreateIfNeeded();
233         impl.shutdownOutput();
234     }
235 
setReceiveBufferSize(int size)236     public void setReceiveBufferSize(int size) throws IOException {
237         impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
238     }
239 
getReceiveBufferSize()240     public int getReceiveBufferSize() throws IOException {
241         return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
242     }
243 
setSoTimeout(int n)244     public void setSoTimeout(int n) throws IOException {
245         impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n));
246     }
247 
getSoTimeout()248     public int getSoTimeout() throws IOException {
249         return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
250     }
251 
setSendBufferSize(int n)252     public void setSendBufferSize(int n) throws IOException {
253         impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n));
254     }
255 
getSendBufferSize()256     public int getSendBufferSize() throws IOException {
257         return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
258     }
259 
260     //???SEC
getRemoteSocketAddress()261     public LocalSocketAddress getRemoteSocketAddress() {
262         throw new UnsupportedOperationException();
263     }
264 
265     //???SEC
isConnected()266     public synchronized boolean isConnected() {
267         return isConnected;
268     }
269 
270     //???SEC
isClosed()271     public boolean isClosed() {
272         throw new UnsupportedOperationException();
273     }
274 
275     //???SEC
isBound()276     public synchronized boolean isBound() {
277         return isBound;
278     }
279 
280     //???SEC
isOutputShutdown()281     public boolean isOutputShutdown() {
282         throw new UnsupportedOperationException();
283     }
284 
285     //???SEC
isInputShutdown()286     public boolean isInputShutdown() {
287         throw new UnsupportedOperationException();
288     }
289 
290     //???SEC
connect(LocalSocketAddress endpoint, int timeout)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      */
setFileDescriptorsForSend(FileDescriptor[] fds)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      */
getAncillaryFileDescriptors()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      */
getPeerCredentials()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      */
getFileDescriptor()338     public FileDescriptor getFileDescriptor() {
339         return impl.getFileDescriptor();
340     }
341 }
342