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