blob: fe7632c254452dcefa31cacdf9eefdcfb54b1da8 [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
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 android.annotation.UnsupportedAppUsage;
20import android.system.ErrnoException;
21import android.system.Int32Ref;
22import android.system.Os;
23import android.system.OsConstants;
24import android.system.StructLinger;
25import android.system.StructTimeval;
26
27import java.io.FileDescriptor;
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.net.SocketOptions;
32
33/**
34 * Socket implementation used for android.net.LocalSocket and
35 * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
36 */
37class LocalSocketImpl
38{
39 private SocketInputStream fis;
40 private SocketOutputStream fos;
41 private Object readMonitor = new Object();
42 private Object writeMonitor = new Object();
43
44 /** null if closed or not yet created */
45 private FileDescriptor fd;
46 /** whether fd is created internally */
47 private boolean mFdCreatedInternally;
48
49 // These fields are accessed by native code;
50 /** file descriptor array received during a previous read */
51 @UnsupportedAppUsage
52 FileDescriptor[] inboundFileDescriptors;
53 /** file descriptor array that should be written during next write */
54 @UnsupportedAppUsage
55 FileDescriptor[] outboundFileDescriptors;
56
57 /**
58 * An input stream for local sockets. Needed because we may
59 * need to read ancillary data.
60 */
61 class SocketInputStream extends InputStream {
62 /** {@inheritDoc} */
63 @Override
64 public int available() throws IOException {
65 FileDescriptor myFd = fd;
66 if (myFd == null) throw new IOException("socket closed");
67
68 Int32Ref avail = new Int32Ref(0);
69 try {
70 Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
71 } catch (ErrnoException e) {
72 throw e.rethrowAsIOException();
73 }
74 return avail.value;
75 }
76
77 /** {@inheritDoc} */
78 @Override
79 public void close() throws IOException {
80 LocalSocketImpl.this.close();
81 }
82
83 /** {@inheritDoc} */
84 @Override
85 public int read() throws IOException {
86 int ret;
87 synchronized (readMonitor) {
88 FileDescriptor myFd = fd;
89 if (myFd == null) throw new IOException("socket closed");
90
91 ret = read_native(myFd);
92 return ret;
93 }
94 }
95
96 /** {@inheritDoc} */
97 @Override
98 public int read(byte[] b) throws IOException {
99 return read(b, 0, b.length);
100 }
101
102 /** {@inheritDoc} */
103 @Override
104 public int read(byte[] b, int off, int len) throws IOException {
105 synchronized (readMonitor) {
106 FileDescriptor myFd = fd;
107 if (myFd == null) throw new IOException("socket closed");
108
109 if (off < 0 || len < 0 || (off + len) > b.length ) {
110 throw new ArrayIndexOutOfBoundsException();
111 }
112
113 int ret = readba_native(b, off, len, myFd);
114
115 return ret;
116 }
117 }
118 }
119
120 /**
121 * An output stream for local sockets. Needed because we may
122 * need to read ancillary data.
123 */
124 class SocketOutputStream extends OutputStream {
125 /** {@inheritDoc} */
126 @Override
127 public void close() throws IOException {
128 LocalSocketImpl.this.close();
129 }
130
131 /** {@inheritDoc} */
132 @Override
133 public void write (byte[] b) throws IOException {
134 write(b, 0, b.length);
135 }
136
137 /** {@inheritDoc} */
138 @Override
139 public void write (byte[] b, int off, int len) throws IOException {
140 synchronized (writeMonitor) {
141 FileDescriptor myFd = fd;
142 if (myFd == null) throw new IOException("socket closed");
143
144 if (off < 0 || len < 0 || (off + len) > b.length ) {
145 throw new ArrayIndexOutOfBoundsException();
146 }
147 writeba_native(b, off, len, myFd);
148 }
149 }
150
151 /** {@inheritDoc} */
152 @Override
153 public void write (int b) throws IOException {
154 synchronized (writeMonitor) {
155 FileDescriptor myFd = fd;
156 if (myFd == null) throw new IOException("socket closed");
157 write_native(b, myFd);
158 }
159 }
160
161 /**
162 * Wait until the data in sending queue is emptied. A polling version
163 * for flush implementation.
164 * @throws IOException
165 * if an i/o error occurs.
166 */
167 @Override
168 public void flush() throws IOException {
169 FileDescriptor myFd = fd;
170 if (myFd == null) throw new IOException("socket closed");
171
172 // Loop until the output buffer is empty.
173 Int32Ref pending = new Int32Ref(0);
174 while (true) {
175 try {
176 // See linux/net/unix/af_unix.c
177 Os.ioctlInt(myFd, OsConstants.TIOCOUTQ, pending);
178 } catch (ErrnoException e) {
179 throw e.rethrowAsIOException();
180 }
181
182 if (pending.value <= 0) {
183 // The output buffer is empty.
184 break;
185 }
186
187 try {
188 Thread.sleep(10);
189 } catch (InterruptedException ie) {
190 break;
191 }
192 }
193 }
194 }
195
196 private native int read_native(FileDescriptor fd) throws IOException;
197 private native int readba_native(byte[] b, int off, int len,
198 FileDescriptor fd) throws IOException;
199 private native void writeba_native(byte[] b, int off, int len,
200 FileDescriptor fd) throws IOException;
201 private native void write_native(int b, FileDescriptor fd)
202 throws IOException;
203 private native void connectLocal(FileDescriptor fd, String name,
204 int namespace) throws IOException;
205 private native void bindLocal(FileDescriptor fd, String name, int namespace)
206 throws IOException;
207 private native Credentials getPeerCredentials_native(
208 FileDescriptor fd) throws IOException;
209
210 /**
211 * Create a new instance.
212 */
213 @UnsupportedAppUsage
214 /*package*/ LocalSocketImpl()
215 {
216 }
217
218 /**
219 * Create a new instance from a file descriptor representing
220 * a bound socket. The state of the file descriptor is not checked here
221 * but the caller can verify socket state by calling listen().
222 *
223 * @param fd non-null; bound file descriptor
224 */
225 /*package*/ LocalSocketImpl(FileDescriptor fd)
226 {
227 this.fd = fd;
228 }
229
230 public String toString() {
231 return super.toString() + " fd:" + fd;
232 }
233
234 /**
235 * Creates a socket in the underlying OS.
236 *
237 * @param sockType either {@link LocalSocket#SOCKET_DGRAM}, {@link LocalSocket#SOCKET_STREAM}
238 * or {@link LocalSocket#SOCKET_SEQPACKET}
239 * @throws IOException
240 */
241 public void create(int sockType) throws IOException {
242 if (fd != null) {
243 throw new IOException("LocalSocketImpl already has an fd");
244 }
245
246 int osType;
247 switch (sockType) {
248 case LocalSocket.SOCKET_DGRAM:
249 osType = OsConstants.SOCK_DGRAM;
250 break;
251 case LocalSocket.SOCKET_STREAM:
252 osType = OsConstants.SOCK_STREAM;
253 break;
254 case LocalSocket.SOCKET_SEQPACKET:
255 osType = OsConstants.SOCK_SEQPACKET;
256 break;
257 default:
258 throw new IllegalStateException("unknown sockType");
259 }
260 try {
261 fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
262 mFdCreatedInternally = true;
263 } catch (ErrnoException e) {
264 e.rethrowAsIOException();
265 }
266 }
267
268 /**
269 * Closes the socket.
270 *
271 * @throws IOException
272 */
273 public void close() throws IOException {
274 synchronized (LocalSocketImpl.this) {
275 if ((fd == null) || (mFdCreatedInternally == false)) {
276 fd = null;
277 return;
278 }
279 try {
280 Os.close(fd);
281 } catch (ErrnoException e) {
282 e.rethrowAsIOException();
283 }
284 fd = null;
285 }
286 }
287
288 /** note timeout presently ignored */
289 protected void connect(LocalSocketAddress address, int timeout)
290 throws IOException
291 {
292 if (fd == null) {
293 throw new IOException("socket not created");
294 }
295
296 connectLocal(fd, address.getName(), address.getNamespace().getId());
297 }
298
299 /**
300 * Binds this socket to an endpoint name. May only be called on an instance
301 * that has not yet been bound.
302 *
303 * @param endpoint endpoint address
304 * @throws IOException
305 */
306 public void bind(LocalSocketAddress endpoint) throws IOException
307 {
308 if (fd == null) {
309 throw new IOException("socket not created");
310 }
311
312 bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId());
313 }
314
315 protected void listen(int backlog) throws IOException
316 {
317 if (fd == null) {
318 throw new IOException("socket not created");
319 }
320 try {
321 Os.listen(fd, backlog);
322 } catch (ErrnoException e) {
323 throw e.rethrowAsIOException();
324 }
325 }
326
327 /**
328 * Accepts a new connection to the socket. Blocks until a new
329 * connection arrives.
330 *
331 * @param s a socket that will be used to represent the new connection.
332 * @throws IOException
333 */
334 protected void accept(LocalSocketImpl s) throws IOException {
335 if (fd == null) {
336 throw new IOException("socket not created");
337 }
338
339 try {
340 s.fd = Os.accept(fd, null /* address */);
341 s.mFdCreatedInternally = true;
342 } catch (ErrnoException e) {
343 throw e.rethrowAsIOException();
344 }
345 }
346
347 /**
348 * Retrieves the input stream for this instance.
349 *
350 * @return input stream
351 * @throws IOException if socket has been closed or cannot be created.
352 */
353 protected InputStream getInputStream() throws IOException
354 {
355 if (fd == null) {
356 throw new IOException("socket not created");
357 }
358
359 synchronized (this) {
360 if (fis == null) {
361 fis = new SocketInputStream();
362 }
363
364 return fis;
365 }
366 }
367
368 /**
369 * Retrieves the output stream for this instance.
370 *
371 * @return output stream
372 * @throws IOException if socket has been closed or cannot be created.
373 */
374 protected OutputStream getOutputStream() throws IOException
375 {
376 if (fd == null) {
377 throw new IOException("socket not created");
378 }
379
380 synchronized (this) {
381 if (fos == null) {
382 fos = new SocketOutputStream();
383 }
384
385 return fos;
386 }
387 }
388
389 /**
390 * Returns the number of bytes available for reading without blocking.
391 *
392 * @return >= 0 count bytes available
393 * @throws IOException
394 */
395 protected int available() throws IOException
396 {
397 return getInputStream().available();
398 }
399
400 /**
401 * Shuts down the input side of the socket.
402 *
403 * @throws IOException
404 */
405 protected void shutdownInput() throws IOException
406 {
407 if (fd == null) {
408 throw new IOException("socket not created");
409 }
410
411 try {
412 Os.shutdown(fd, OsConstants.SHUT_RD);
413 } catch (ErrnoException e) {
414 throw e.rethrowAsIOException();
415 }
416 }
417
418 /**
419 * Shuts down the output side of the socket.
420 *
421 * @throws IOException
422 */
423 protected void shutdownOutput() throws IOException
424 {
425 if (fd == null) {
426 throw new IOException("socket not created");
427 }
428
429 try {
430 Os.shutdown(fd, OsConstants.SHUT_WR);
431 } catch (ErrnoException e) {
432 throw e.rethrowAsIOException();
433 }
434 }
435
436 protected FileDescriptor getFileDescriptor()
437 {
438 return fd;
439 }
440
441 protected boolean supportsUrgentData()
442 {
443 return false;
444 }
445
446 protected void sendUrgentData(int data) throws IOException
447 {
448 throw new RuntimeException ("not impled");
449 }
450
451 public Object getOption(int optID) throws IOException
452 {
453 if (fd == null) {
454 throw new IOException("socket not created");
455 }
456
457 try {
458 Object toReturn;
459 switch (optID) {
460 case SocketOptions.SO_TIMEOUT:
461 StructTimeval timeval = Os.getsockoptTimeval(fd, OsConstants.SOL_SOCKET,
462 OsConstants.SO_SNDTIMEO);
463 toReturn = (int) timeval.toMillis();
464 break;
465 case SocketOptions.SO_RCVBUF:
466 case SocketOptions.SO_SNDBUF:
467 case SocketOptions.SO_REUSEADDR:
468 int osOpt = javaSoToOsOpt(optID);
469 toReturn = Os.getsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt);
470 break;
471 case SocketOptions.SO_LINGER:
472 StructLinger linger=
473 Os.getsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER);
474 if (!linger.isOn()) {
475 toReturn = -1;
476 } else {
477 toReturn = linger.l_linger;
478 }
479 break;
480 case SocketOptions.TCP_NODELAY:
481 toReturn = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
482 OsConstants.TCP_NODELAY);
483 break;
484 default:
485 throw new IOException("Unknown option: " + optID);
486 }
487 return toReturn;
488 } catch (ErrnoException e) {
489 throw e.rethrowAsIOException();
490 }
491 }
492
493 public void setOption(int optID, Object value)
494 throws IOException {
495
496 if (fd == null) {
497 throw new IOException("socket not created");
498 }
499
500 /*
501 * Boolean.FALSE is used to disable some options, so it
502 * is important to distinguish between FALSE and unset.
503 * We define it here that -1 is unset, 0 is FALSE, and 1
504 * is TRUE.
505 */
506 int boolValue = -1;
507 int intValue = 0;
508 if (value instanceof Integer) {
509 intValue = (Integer)value;
510 } else if (value instanceof Boolean) {
511 boolValue = ((Boolean) value)? 1 : 0;
512 } else {
513 throw new IOException("bad value: " + value);
514 }
515
516 try {
517 switch (optID) {
518 case SocketOptions.SO_LINGER:
519 StructLinger linger = new StructLinger(boolValue, intValue);
520 Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
521 break;
522 case SocketOptions.SO_TIMEOUT:
523 // The option must set both send and receive timeouts.
524 // Note: The incoming timeout value is in milliseconds.
525 StructTimeval timeval = StructTimeval.fromMillis(intValue);
526 Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
527 timeval);
528 Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
529 timeval);
530 break;
531 case SocketOptions.SO_RCVBUF:
532 case SocketOptions.SO_SNDBUF:
533 case SocketOptions.SO_REUSEADDR:
534 int osOpt = javaSoToOsOpt(optID);
535 Os.setsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt, intValue);
536 break;
537 case SocketOptions.TCP_NODELAY:
538 Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_NODELAY,
539 intValue);
540 break;
541 default:
542 throw new IOException("Unknown option: " + optID);
543 }
544 } catch (ErrnoException e) {
545 throw e.rethrowAsIOException();
546 }
547 }
548
549 /**
550 * Enqueues a set of file descriptors to send to the peer. The queue
551 * is one deep. The file descriptors will be sent with the next write
552 * of normal data, and will be delivered in a single ancillary message.
553 * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
554 *
555 * @param fds non-null; file descriptors to send.
556 * @throws IOException
557 */
558 public void setFileDescriptorsForSend(FileDescriptor[] fds) {
559 synchronized(writeMonitor) {
560 outboundFileDescriptors = fds;
561 }
562 }
563
564 /**
565 * Retrieves a set of file descriptors that a peer has sent through
566 * an ancillary message. This method retrieves the most recent set sent,
567 * and then returns null until a new set arrives.
568 * File descriptors may only be passed along with regular data, so this
569 * method can only return a non-null after a read operation.
570 *
571 * @return null or file descriptor array
572 * @throws IOException
573 */
574 public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
575 synchronized(readMonitor) {
576 FileDescriptor[] result = inboundFileDescriptors;
577
578 inboundFileDescriptors = null;
579 return result;
580 }
581 }
582
583 /**
584 * Retrieves the credentials of this socket's peer. Only valid on
585 * connected sockets.
586 *
587 * @return non-null; peer credentials
588 * @throws IOException
589 */
590 public Credentials getPeerCredentials() throws IOException {
591 return getPeerCredentials_native(fd);
592 }
593
594 /**
595 * Retrieves the socket name from the OS.
596 *
597 * @return non-null; socket name
598 * @throws IOException on failure
599 */
600 public LocalSocketAddress getSockAddress() throws IOException {
601 // This method has never been implemented.
602 return null;
603 }
604
605 @Override
606 protected void finalize() throws IOException {
607 close();
608 }
609
610 private static int javaSoToOsOpt(int optID) {
611 switch (optID) {
612 case SocketOptions.SO_SNDBUF:
613 return OsConstants.SO_SNDBUF;
614 case SocketOptions.SO_RCVBUF:
615 return OsConstants.SO_RCVBUF;
616 case SocketOptions.SO_REUSEADDR:
617 return OsConstants.SO_REUSEADDR;
618 default:
619 throw new UnsupportedOperationException("Unknown option: " + optID);
620 }
621 }
622}