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