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