blob: 5b38f78782a8ca9a6598365b2341bd63f80612c1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Artur Satayev26958002019-12-10 17:47:52 +000019import android.compat.annotation.UnsupportedAppUsage;
20
Jeff Sharkey065b2992012-08-05 14:16:48 -070021import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import java.io.FileDescriptor;
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.OutputStream;
26import java.net.SocketOptions;
27
28/**
29 * Creates a (non-server) socket in the UNIX-domain namespace. The interface
Neil Fullerbf0dc0f2015-11-24 18:19:06 +000030 * 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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032 */
Jeff Sharkey065b2992012-08-05 14:16:48 -070033public class LocalSocket implements Closeable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Mathew Inwood53f089f2018-08-08 14:44:44 +010035 @UnsupportedAppUsage
Ian Rogersd8e34a62014-08-27 16:32:57 -070036 private final LocalSocketImpl impl;
Neil Fuller7fd72462017-01-06 11:29:15 +000037 /** false if impl.create() needs to be called */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 private volatile boolean implCreated;
39 private LocalSocketAddress localAddress;
40 private boolean isBound;
41 private boolean isConnected;
Mike Lockwoode7d309a2013-07-16 11:36:22 -070042 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
53 /**
54 * Creates a AF_LOCAL/UNIX domain stream socket.
55 */
56 public LocalSocket() {
Mike Lockwoode7d309a2013-07-16 11:36:22 -070057 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 */
66 public LocalSocket(int sockType) {
67 this(new LocalSocketImpl(), sockType);
zzy3b147b72012-04-03 19:48:32 -070068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
Neil Fullerb08c7bc2017-01-04 10:07:25 +000070 private LocalSocket(LocalSocketImpl impl, int sockType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 this.impl = impl;
Mike Lockwoode7d309a2013-07-16 11:36:22 -070072 this.sockType = sockType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 this.isConnected = false;
74 this.isBound = false;
75 }
76
Neil Fullerb08c7bc2017-01-04 10:07:25 +000077 /**
Neil Fuller7fd72462017-01-06 11:29:15 +000078 * 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 */
84 public static LocalSocket createConnectedLocalSocket(FileDescriptor fd) {
85 return createConnectedLocalSocket(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
86 }
87
88 /**
Neil Fullerb08c7bc2017-01-04 10:07:25 +000089 * for use with LocalServerSocket.accept()
90 */
Neil Fuller7fd72462017-01-06 11:29:15 +000091 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 */
98 private static LocalSocket createConnectedLocalSocket(LocalSocketImpl impl, int sockType) {
Neil Fullerb08c7bc2017-01-04 10:07:25 +000099 LocalSocket socket = new LocalSocket(impl, sockType);
100 socket.isConnected = true;
101 socket.isBound = true;
102 socket.implCreated = true;
103 return socket;
104 }
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 /** {@inheritDoc} */
107 @Override
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 */
119 private void implCreateIfNeeded() throws IOException {
120 if (!implCreated) {
121 synchronized (this) {
122 if (!implCreated) {
Jesse Wilsonc59a6622010-09-21 10:26:57 -0700123 try {
Mike Lockwoode7d309a2013-07-16 11:36:22 -0700124 impl.create(sockType);
Jesse Wilsonc59a6622010-09-21 10:26:57 -0700125 } finally {
126 implCreated = true;
127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 }
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 */
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 */
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 */
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 */
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 */
201 public OutputStream getOutputStream() throws IOException {
202 implCreateIfNeeded();
203 return impl.getOutputStream();
204 }
205
206 /**
207 * Closes the socket.
208 *
209 * @throws IOException
210 */
Jeff Sharkey065b2992012-08-05 14:16:48 -0700211 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 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 */
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 */
232 public void shutdownOutput() throws IOException {
233 implCreateIfNeeded();
234 impl.shutdownOutput();
235 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 public void setReceiveBufferSize(int size) throws IOException {
238 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
239 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 public int getReceiveBufferSize() throws IOException {
242 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
243 }
244
245 public void setSoTimeout(int n) throws IOException {
246 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n));
247 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 public int getSoTimeout() throws IOException {
250 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
251 }
252
253 public void setSendBufferSize(int n) throws IOException {
254 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n));
255 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 public int getSendBufferSize() throws IOException {
258 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
259 }
260
261 //???SEC
262 public LocalSocketAddress getRemoteSocketAddress() {
263 throw new UnsupportedOperationException();
264 }
265
266 //???SEC
267 public synchronized boolean isConnected() {
268 return isConnected;
269 }
270
271 //???SEC
272 public boolean isClosed() {
273 throw new UnsupportedOperationException();
274 }
275
276 //???SEC
277 public synchronized boolean isBound() {
278 return isBound;
279 }
280
281 //???SEC
282 public boolean isOutputShutdown() {
283 throw new UnsupportedOperationException();
284 }
285
286 //???SEC
287 public boolean isInputShutdown() {
288 throw new UnsupportedOperationException();
289 }
290
291 //???SEC
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 */
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 */
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 */
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 */
339 public FileDescriptor getFileDescriptor() {
340 return impl.getFileDescriptor();
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342}