blob: 3b43c36c43a914c15a4c77ce67fd2f54373fdc10 [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
19import java.io.IOException;
20import java.io.OutputStream;
21import java.io.InputStream;
22import java.io.FileDescriptor;
23import java.net.SocketOptions;
24
25/**
26 * Socket implementation used for android.net.LocalSocket and
27 * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
28 */
29class LocalSocketImpl
30{
31 private SocketInputStream fis;
32 private SocketOutputStream fos;
33 private Object readMonitor = new Object();
34 private Object writeMonitor = new Object();
35
36 /** null if closed or not yet created */
37 private FileDescriptor fd;
38
39 // These fields are accessed by native code;
40 /** file descriptor array received during a previous read */
41 FileDescriptor[] inboundFileDescriptors;
42 /** file descriptor array that should be written during next write */
43 FileDescriptor[] outboundFileDescriptors;
44
45 /**
46 * An input stream for local sockets. Needed because we may
47 * need to read ancillary data.
48 */
49 class SocketInputStream extends InputStream {
50 /** {@inheritDoc} */
51 @Override
52 public int available() throws IOException {
53 return available_native(fd);
54 }
55
56 /** {@inheritDoc} */
57 @Override
58 public void close() throws IOException {
59 LocalSocketImpl.this.close();
60 }
61
62 /** {@inheritDoc} */
63 @Override
64 public int read() throws IOException {
65 int ret;
66 synchronized (readMonitor) {
67 FileDescriptor myFd = fd;
68 if (myFd == null) throw new IOException("socket closed");
69
70 ret = read_native(myFd);
71 return ret;
72 }
73 }
74
75 /** {@inheritDoc} */
76 @Override
77 public int read(byte[] b) throws IOException {
78 return read(b, 0, b.length);
79 }
80
81 /** {@inheritDoc} */
82 @Override
83 public int read(byte[] b, int off, int len) throws IOException {
84 synchronized (readMonitor) {
85 FileDescriptor myFd = fd;
86 if (myFd == null) throw new IOException("socket closed");
87
88 if (off < 0 || len < 0 || (off + len) > b.length ) {
89 throw new ArrayIndexOutOfBoundsException();
90 }
91
92 int ret = readba_native(b, off, len, myFd);
93
94 return ret;
95 }
96 }
97 }
98
99 /**
100 * An output stream for local sockets. Needed because we may
101 * need to read ancillary data.
102 */
103 class SocketOutputStream extends OutputStream {
104 /** {@inheritDoc} */
105 @Override
106 public void close() throws IOException {
107 LocalSocketImpl.this.close();
108 }
109
110 /** {@inheritDoc} */
111 @Override
112 public void write (byte[] b) throws IOException {
113 write(b, 0, b.length);
114 }
115
116 /** {@inheritDoc} */
117 @Override
118 public void write (byte[] b, int off, int len) throws IOException {
119 synchronized (writeMonitor) {
120 FileDescriptor myFd = fd;
121 if (myFd == null) throw new IOException("socket closed");
122
123 if (off < 0 || len < 0 || (off + len) > b.length ) {
124 throw new ArrayIndexOutOfBoundsException();
125 }
126 writeba_native(b, off, len, myFd);
127 }
128 }
129
130 /** {@inheritDoc} */
131 @Override
132 public void write (int b) throws IOException {
133 synchronized (writeMonitor) {
134 FileDescriptor myFd = fd;
135 if (myFd == null) throw new IOException("socket closed");
136 write_native(b, myFd);
137 }
138 }
zzy71bfafc2013-04-16 17:17:37 -0700139
140 /**
141 * Wait until the data in sending queue is emptied. A polling version
142 * for flush implementation.
143 * @throws IOException
144 * if an i/o error occurs.
145 */
146 @Override
147 public void flush() throws IOException {
148 FileDescriptor myFd = fd;
149 if (myFd == null) throw new IOException("socket closed");
Matthew Xied073bfd2013-05-03 17:27:14 -0700150 while(pending_native(myFd) > 0) {
zzy71bfafc2013-04-16 17:17:37 -0700151 try {
152 Thread.sleep(10);
153 } catch (InterruptedException ie) {
154 return;
155 }
156 }
157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
159
zzy71bfafc2013-04-16 17:17:37 -0700160 private native int pending_native(FileDescriptor fd) throws IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 private native int available_native(FileDescriptor fd) throws IOException;
162 private native void close_native(FileDescriptor fd) throws IOException;
163 private native int read_native(FileDescriptor fd) throws IOException;
164 private native int readba_native(byte[] b, int off, int len,
165 FileDescriptor fd) throws IOException;
166 private native void writeba_native(byte[] b, int off, int len,
167 FileDescriptor fd) throws IOException;
168 private native void write_native(int b, FileDescriptor fd)
169 throws IOException;
170 private native void connectLocal(FileDescriptor fd, String name,
171 int namespace) throws IOException;
172 private native void bindLocal(FileDescriptor fd, String name, int namespace)
173 throws IOException;
174 private native FileDescriptor create_native(boolean stream)
175 throws IOException;
176 private native void listen_native(FileDescriptor fd, int backlog)
177 throws IOException;
178 private native void shutdown(FileDescriptor fd, boolean shutdownInput);
179 private native Credentials getPeerCredentials_native(
180 FileDescriptor fd) throws IOException;
181 private native int getOption_native(FileDescriptor fd, int optID)
182 throws IOException;
183 private native void setOption_native(FileDescriptor fd, int optID,
184 int b, int value) throws IOException;
185
186// private native LocalSocketAddress getSockName_native
187// (FileDescriptor fd) throws IOException;
188
189 /**
190 * Accepts a connection on a server socket.
191 *
192 * @param fd file descriptor of server socket
193 * @param s socket implementation that will become the new socket
194 * @return file descriptor of new socket
195 */
196 private native FileDescriptor accept
197 (FileDescriptor fd, LocalSocketImpl s) throws IOException;
198
199 /**
200 * Create a new instance.
201 */
202 /*package*/ LocalSocketImpl()
203 {
204 }
205
206 /**
207 * Create a new instance from a file descriptor representing
208 * a bound socket. The state of the file descriptor is not checked here
209 * but the caller can verify socket state by calling listen().
210 *
211 * @param fd non-null; bound file descriptor
212 */
213 /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
214 {
215 this.fd = fd;
216 }
217
218 public String toString() {
219 return super.toString() + " fd:" + fd;
220 }
221
222 /**
223 * Creates a socket in the underlying OS.
224 *
225 * @param stream true if this should be a stream socket, false for
226 * datagram.
227 * @throws IOException
228 */
229 public void create (boolean stream) throws IOException {
230 // no error if socket already created
231 // need this for LocalServerSocket.accept()
232 if (fd == null) {
233 fd = create_native(stream);
234 }
235 }
236
237 /**
238 * Closes the socket.
239 *
240 * @throws IOException
241 */
242 public void close() throws IOException {
243 synchronized (LocalSocketImpl.this) {
244 if (fd == null) return;
245 close_native(fd);
246 fd = null;
247 }
248 }
249
250 /** note timeout presently ignored */
251 protected void connect(LocalSocketAddress address, int timeout)
252 throws IOException
253 {
254 if (fd == null) {
255 throw new IOException("socket not created");
256 }
257
258 connectLocal(fd, address.getName(), address.getNamespace().getId());
259 }
260
261 /**
262 * Binds this socket to an endpoint name. May only be called on an instance
263 * that has not yet been bound.
264 *
265 * @param endpoint endpoint address
266 * @throws IOException
267 */
268 public void bind(LocalSocketAddress endpoint) throws IOException
269 {
270 if (fd == null) {
271 throw new IOException("socket not created");
272 }
273
274 bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId());
275 }
276
277 protected void listen(int backlog) throws IOException
278 {
279 if (fd == null) {
280 throw new IOException("socket not created");
281 }
282
283 listen_native(fd, backlog);
284 }
285
286 /**
287 * Accepts a new connection to the socket. Blocks until a new
288 * connection arrives.
289 *
290 * @param s a socket that will be used to represent the new connection.
291 * @throws IOException
292 */
293 protected void accept(LocalSocketImpl s) throws IOException
294 {
295 if (fd == null) {
296 throw new IOException("socket not created");
297 }
298
299 s.fd = accept(fd, s);
300 }
301
302 /**
303 * Retrieves the input stream for this instance.
304 *
305 * @return input stream
306 * @throws IOException if socket has been closed or cannot be created.
307 */
308 protected InputStream getInputStream() throws IOException
309 {
310 if (fd == null) {
311 throw new IOException("socket not created");
312 }
313
314 synchronized (this) {
315 if (fis == null) {
316 fis = new SocketInputStream();
317 }
318
319 return fis;
320 }
321 }
322
323 /**
324 * Retrieves the output stream for this instance.
325 *
326 * @return output stream
327 * @throws IOException if socket has been closed or cannot be created.
328 */
329 protected OutputStream getOutputStream() throws IOException
330 {
331 if (fd == null) {
332 throw new IOException("socket not created");
333 }
334
335 synchronized (this) {
336 if (fos == null) {
337 fos = new SocketOutputStream();
338 }
339
340 return fos;
341 }
342 }
343
344 /**
345 * Returns the number of bytes available for reading without blocking.
346 *
347 * @return >= 0 count bytes available
348 * @throws IOException
349 */
350 protected int available() throws IOException
351 {
352 return getInputStream().available();
353 }
354
355 /**
356 * Shuts down the input side of the socket.
357 *
358 * @throws IOException
359 */
360 protected void shutdownInput() throws IOException
361 {
362 if (fd == null) {
363 throw new IOException("socket not created");
364 }
365
366 shutdown(fd, true);
367 }
368
369 /**
370 * Shuts down the output side of the socket.
371 *
372 * @throws IOException
373 */
374 protected void shutdownOutput() throws IOException
375 {
376 if (fd == null) {
377 throw new IOException("socket not created");
378 }
379
380 shutdown(fd, false);
381 }
382
383 protected FileDescriptor getFileDescriptor()
384 {
385 return fd;
386 }
387
388 protected boolean supportsUrgentData()
389 {
390 return false;
391 }
392
393 protected void sendUrgentData(int data) throws IOException
394 {
395 throw new RuntimeException ("not impled");
396 }
397
398 public Object getOption(int optID) throws IOException
399 {
400 if (fd == null) {
401 throw new IOException("socket not created");
402 }
403
404 if (optID == SocketOptions.SO_TIMEOUT) {
405 return 0;
406 }
407
408 int value = getOption_native(fd, optID);
409 switch (optID)
410 {
411 case SocketOptions.SO_RCVBUF:
412 case SocketOptions.SO_SNDBUF:
413 return value;
414 case SocketOptions.SO_REUSEADDR:
415 default:
416 return value;
417 }
418 }
419
420 public void setOption(int optID, Object value)
421 throws IOException {
422 /*
423 * Boolean.FALSE is used to disable some options, so it
424 * is important to distinguish between FALSE and unset.
425 * We define it here that -1 is unset, 0 is FALSE, and 1
426 * is TRUE.
427 */
428 int boolValue = -1;
429 int intValue = 0;
430
431 if (fd == null) {
432 throw new IOException("socket not created");
433 }
434
435 if (value instanceof Integer) {
436 intValue = (Integer)value;
437 } else if (value instanceof Boolean) {
438 boolValue = ((Boolean) value)? 1 : 0;
439 } else {
440 throw new IOException("bad value: " + value);
441 }
442
443 setOption_native(fd, optID, boolValue, intValue);
444 }
445
446 /**
447 * Enqueues a set of file descriptors to send to the peer. The queue
448 * is one deep. The file descriptors will be sent with the next write
449 * of normal data, and will be delivered in a single ancillary message.
450 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
451 *
452 * @param fds non-null; file descriptors to send.
453 * @throws IOException
454 */
455 public void setFileDescriptorsForSend(FileDescriptor[] fds) {
456 synchronized(writeMonitor) {
457 outboundFileDescriptors = fds;
458 }
459 }
460
461 /**
462 * Retrieves a set of file descriptors that a peer has sent through
463 * an ancillary message. This method retrieves the most recent set sent,
464 * and then returns null until a new set arrives.
465 * File descriptors may only be passed along with regular data, so this
466 * method can only return a non-null after a read operation.
467 *
468 * @return null or file descriptor array
469 * @throws IOException
470 */
471 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
472 synchronized(readMonitor) {
473 FileDescriptor[] result = inboundFileDescriptors;
474
475 inboundFileDescriptors = null;
476 return result;
477 }
478 }
479
480 /**
481 * Retrieves the credentials of this socket's peer. Only valid on
482 * connected sockets.
483 *
484 * @return non-null; peer credentials
485 * @throws IOException
486 */
487 public Credentials getPeerCredentials() throws IOException
488 {
489 return getPeerCredentials_native(fd);
490 }
491
492 /**
493 * Retrieves the socket name from the OS.
494 *
495 * @return non-null; socket name
496 * @throws IOException on failure
497 */
498 public LocalSocketAddress getSockAddress() throws IOException
499 {
500 return null;
501 //TODO implement this
502 //return getSockName_native(fd);
503 }
504
505 @Override
506 protected void finalize() throws IOException {
507 close();
508 }
509}
510