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