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