• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.net;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.system.ErrnoException;
21 import android.system.Int32Ref;
22 import android.system.Os;
23 import android.system.OsConstants;
24 import android.system.StructLinger;
25 import android.system.StructTimeval;
26 
27 import java.io.FileDescriptor;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.net.SocketOptions;
32 
33 /**
34  * Socket implementation used for android.net.LocalSocket and
35  * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
36  */
37 class 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
available()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
close()79         public void close() throws IOException {
80             LocalSocketImpl.this.close();
81         }
82 
83         /** {@inheritDoc} */
84         @Override
read()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
read(byte[] b)98         public int read(byte[] b) throws IOException {
99             return read(b, 0, b.length);
100         }
101 
102         /** {@inheritDoc} */
103         @Override
read(byte[] b, int off, int len)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
close()127         public void close() throws IOException {
128             LocalSocketImpl.this.close();
129         }
130 
131         /** {@inheritDoc} */
132         @Override
write(byte[] b)133         public void write (byte[] b) throws IOException {
134             write(b, 0, b.length);
135         }
136 
137         /** {@inheritDoc} */
138         @Override
write(byte[] b, int off, int len)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
write(int b)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
flush()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 
read_native(FileDescriptor fd)196     private native int read_native(FileDescriptor fd) throws IOException;
readba_native(byte[] b, int off, int len, FileDescriptor fd)197     private native int readba_native(byte[] b, int off, int len,
198             FileDescriptor fd) throws IOException;
writeba_native(byte[] b, int off, int len, FileDescriptor fd)199     private native void writeba_native(byte[] b, int off, int len,
200             FileDescriptor fd) throws IOException;
write_native(int b, FileDescriptor fd)201     private native void write_native(int b, FileDescriptor fd)
202             throws IOException;
connectLocal(FileDescriptor fd, String name, int namespace)203     private native void connectLocal(FileDescriptor fd, String name,
204             int namespace) throws IOException;
bindLocal(FileDescriptor fd, String name, int namespace)205     private native void bindLocal(FileDescriptor fd, String name, int namespace)
206             throws IOException;
getPeerCredentials_native( FileDescriptor fd)207     private native Credentials getPeerCredentials_native(
208             FileDescriptor fd) throws IOException;
209 
210     /**
211      * Create a new instance.
212      */
213     @UnsupportedAppUsage
LocalSocketImpl()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      */
LocalSocketImpl(FileDescriptor fd)225     /*package*/ LocalSocketImpl(FileDescriptor fd)
226     {
227         this.fd = fd;
228     }
229 
toString()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      */
create(int sockType)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      */
close()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 */
connect(LocalSocketAddress address, int timeout)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      */
bind(LocalSocketAddress endpoint)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 
listen(int backlog)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      */
accept(LocalSocketImpl s)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      */
getInputStream()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      */
getOutputStream()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      */
available()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      */
shutdownInput()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      */
shutdownOutput()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 
getFileDescriptor()436     protected FileDescriptor getFileDescriptor()
437     {
438         return fd;
439     }
440 
supportsUrgentData()441     protected boolean supportsUrgentData()
442     {
443         return false;
444     }
445 
sendUrgentData(int data)446     protected void sendUrgentData(int data) throws IOException
447     {
448         throw new RuntimeException ("not impled");
449     }
450 
getOption(int optID)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 
setOption(int optID, Object value)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      */
setFileDescriptorsForSend(FileDescriptor[] fds)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      */
getAncillaryFileDescriptors()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      */
getPeerCredentials()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      */
getSockAddress()600     public LocalSocketAddress getSockAddress() throws IOException {
601         // This method has never been implemented.
602         return null;
603     }
604 
605     @Override
finalize()606     protected void finalize() throws IOException {
607         close();
608     }
609 
javaSoToOsOpt(int optID)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 }
623