blob: 8afa1ed3e4a52eff471f20adbb397053af7c69c8 [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
Jeff Sharkey065b2992012-08-05 14:16:48 -070019import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import java.io.FileDescriptor;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.OutputStream;
24import java.net.SocketOptions;
25
26/**
27 * Creates a (non-server) socket in the UNIX-domain namespace. The interface
Neil Fullerbf0dc0f2015-11-24 18:19:06 +000028 * 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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030 */
Jeff Sharkey065b2992012-08-05 14:16:48 -070031public class LocalSocket implements Closeable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Ian Rogersd8e34a62014-08-27 16:32:57 -070033 private final LocalSocketImpl impl;
Neil Fuller7fd72462017-01-06 11:29:15 +000034 /** false if impl.create() needs to be called */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 private volatile boolean implCreated;
36 private LocalSocketAddress localAddress;
37 private boolean isBound;
38 private boolean isConnected;
Mike Lockwoode7d309a2013-07-16 11:36:22 -070039 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50 /**
51 * Creates a AF_LOCAL/UNIX domain stream socket.
52 */
53 public LocalSocket() {
Mike Lockwoode7d309a2013-07-16 11:36:22 -070054 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 */
63 public LocalSocket(int sockType) {
64 this(new LocalSocketImpl(), sockType);
zzy3b147b72012-04-03 19:48:32 -070065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
Neil Fullerb08c7bc2017-01-04 10:07:25 +000067 private LocalSocket(LocalSocketImpl impl, int sockType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 this.impl = impl;
Mike Lockwoode7d309a2013-07-16 11:36:22 -070069 this.sockType = sockType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 this.isConnected = false;
71 this.isBound = false;
72 }
73
Neil Fullerb08c7bc2017-01-04 10:07:25 +000074 /**
Neil Fuller7fd72462017-01-06 11:29:15 +000075 * 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 */
81 public static LocalSocket createConnectedLocalSocket(FileDescriptor fd) {
82 return createConnectedLocalSocket(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
83 }
84
85 /**
Neil Fullerb08c7bc2017-01-04 10:07:25 +000086 * for use with LocalServerSocket.accept()
87 */
Neil Fuller7fd72462017-01-06 11:29:15 +000088 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 */
95 private static LocalSocket createConnectedLocalSocket(LocalSocketImpl impl, int sockType) {
Neil Fullerb08c7bc2017-01-04 10:07:25 +000096 LocalSocket socket = new LocalSocket(impl, sockType);
97 socket.isConnected = true;
98 socket.isBound = true;
99 socket.implCreated = true;
100 return socket;
101 }
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 /** {@inheritDoc} */
104 @Override
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 */
116 private void implCreateIfNeeded() throws IOException {
117 if (!implCreated) {
118 synchronized (this) {
119 if (!implCreated) {
Jesse Wilsonc59a6622010-09-21 10:26:57 -0700120 try {
Mike Lockwoode7d309a2013-07-16 11:36:22 -0700121 impl.create(sockType);
Jesse Wilsonc59a6622010-09-21 10:26:57 -0700122 } finally {
123 implCreated = true;
124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 }
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 */
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 */
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 */
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 */
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 */
198 public OutputStream getOutputStream() throws IOException {
199 implCreateIfNeeded();
200 return impl.getOutputStream();
201 }
202
203 /**
204 * Closes the socket.
205 *
206 * @throws IOException
207 */
Jeff Sharkey065b2992012-08-05 14:16:48 -0700208 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 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 */
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 */
229 public void shutdownOutput() throws IOException {
230 implCreateIfNeeded();
231 impl.shutdownOutput();
232 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 public void setReceiveBufferSize(int size) throws IOException {
235 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
236 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 public int getReceiveBufferSize() throws IOException {
239 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
240 }
241
242 public void setSoTimeout(int n) throws IOException {
243 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n));
244 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 public int getSoTimeout() throws IOException {
247 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
248 }
249
250 public void setSendBufferSize(int n) throws IOException {
251 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n));
252 }
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 public int getSendBufferSize() throws IOException {
255 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
256 }
257
258 //???SEC
259 public LocalSocketAddress getRemoteSocketAddress() {
260 throw new UnsupportedOperationException();
261 }
262
263 //???SEC
264 public synchronized boolean isConnected() {
265 return isConnected;
266 }
267
268 //???SEC
269 public boolean isClosed() {
270 throw new UnsupportedOperationException();
271 }
272
273 //???SEC
274 public synchronized boolean isBound() {
275 return isBound;
276 }
277
278 //???SEC
279 public boolean isOutputShutdown() {
280 throw new UnsupportedOperationException();
281 }
282
283 //???SEC
284 public boolean isInputShutdown() {
285 throw new UnsupportedOperationException();
286 }
287
288 //???SEC
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 */
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 */
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 */
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 */
336 public FileDescriptor getFileDescriptor() {
337 return impl.getFileDescriptor();
Ajay Panicker7a8c36a2017-01-05 15:38:52 -0800338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339}