• 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 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 /**
26  * Socket implementation used for android.net.LocalSocket and
27  * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
28  */
29 class 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
available()52         public int available() throws IOException {
53             return available_native(fd);
54         }
55 
56         /** {@inheritDoc} */
57         @Override
close()58         public void close() throws IOException {
59             LocalSocketImpl.this.close();
60         }
61 
62         /** {@inheritDoc} */
63         @Override
read()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
read(byte[] b)77         public int read(byte[] b) throws IOException {
78             return read(b, 0, b.length);
79         }
80 
81         /** {@inheritDoc} */
82         @Override
read(byte[] b, int off, int len)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
close()106         public void close() throws IOException {
107             LocalSocketImpl.this.close();
108         }
109 
110         /** {@inheritDoc} */
111         @Override
write(byte[] b)112         public void write (byte[] b) throws IOException {
113             write(b, 0, b.length);
114         }
115 
116         /** {@inheritDoc} */
117         @Override
write(byte[] b, int off, int len)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
write(int b)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         }
139     }
140 
available_native(FileDescriptor fd)141     private native int available_native(FileDescriptor fd) throws IOException;
close_native(FileDescriptor fd)142     private native void close_native(FileDescriptor fd) throws IOException;
read_native(FileDescriptor fd)143     private native int read_native(FileDescriptor fd) throws IOException;
readba_native(byte[] b, int off, int len, FileDescriptor fd)144     private native int readba_native(byte[] b, int off, int len,
145             FileDescriptor fd) throws IOException;
writeba_native(byte[] b, int off, int len, FileDescriptor fd)146     private native void writeba_native(byte[] b, int off, int len,
147             FileDescriptor fd) throws IOException;
write_native(int b, FileDescriptor fd)148     private native void write_native(int b, FileDescriptor fd)
149             throws IOException;
connectLocal(FileDescriptor fd, String name, int namespace)150     private native void connectLocal(FileDescriptor fd, String name,
151             int namespace) throws IOException;
bindLocal(FileDescriptor fd, String name, int namespace)152     private native void bindLocal(FileDescriptor fd, String name, int namespace)
153             throws IOException;
create_native(boolean stream)154     private native FileDescriptor create_native(boolean stream)
155             throws IOException;
listen_native(FileDescriptor fd, int backlog)156     private native void listen_native(FileDescriptor fd, int backlog)
157             throws IOException;
shutdown(FileDescriptor fd, boolean shutdownInput)158     private native void shutdown(FileDescriptor fd, boolean shutdownInput);
getPeerCredentials_native( FileDescriptor fd)159     private native Credentials getPeerCredentials_native(
160             FileDescriptor fd) throws IOException;
getOption_native(FileDescriptor fd, int optID)161     private native int getOption_native(FileDescriptor fd, int optID)
162             throws IOException;
setOption_native(FileDescriptor fd, int optID, int b, int value)163     private native void setOption_native(FileDescriptor fd, int optID,
164             int b, int value) throws IOException;
165 
166 //    private native LocalSocketAddress getSockName_native
167 //            (FileDescriptor fd) throws IOException;
168 
169     /**
170      * Accepts a connection on a server socket.
171      *
172      * @param fd file descriptor of server socket
173      * @param s socket implementation that will become the new socket
174      * @return file descriptor of new socket
175      */
accept(FileDescriptor fd, LocalSocketImpl s)176     private native FileDescriptor accept
177             (FileDescriptor fd, LocalSocketImpl s) throws IOException;
178 
179     /**
180      * Create a new instance.
181      */
LocalSocketImpl()182     /*package*/ LocalSocketImpl()
183     {
184     }
185 
186     /**
187      * Create a new instance from a file descriptor representing
188      * a bound socket. The state of the file descriptor is not checked here
189      *  but the caller can verify socket state by calling listen().
190      *
191      * @param fd non-null; bound file descriptor
192      */
LocalSocketImpl(FileDescriptor fd)193     /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
194     {
195         this.fd = fd;
196     }
197 
toString()198     public String toString() {
199         return super.toString() + " fd:" + fd;
200     }
201 
202     /**
203      * Creates a socket in the underlying OS.
204      *
205      * @param stream true if this should be a stream socket, false for
206      * datagram.
207      * @throws IOException
208      */
create(boolean stream)209     public void create (boolean stream) throws IOException {
210         // no error if socket already created
211         // need this for LocalServerSocket.accept()
212         if (fd == null) {
213             fd = create_native(stream);
214         }
215     }
216 
217     /**
218      * Closes the socket.
219      *
220      * @throws IOException
221      */
close()222     public void close() throws IOException {
223         synchronized (LocalSocketImpl.this) {
224             if (fd == null) return;
225             close_native(fd);
226             fd = null;
227         }
228     }
229 
230     /** note timeout presently ignored */
connect(LocalSocketAddress address, int timeout)231     protected void connect(LocalSocketAddress address, int timeout)
232                         throws IOException
233     {
234         if (fd == null) {
235             throw new IOException("socket not created");
236         }
237 
238         connectLocal(fd, address.getName(), address.getNamespace().getId());
239     }
240 
241     /**
242      * Binds this socket to an endpoint name. May only be called on an instance
243      * that has not yet been bound.
244      *
245      * @param endpoint endpoint address
246      * @throws IOException
247      */
bind(LocalSocketAddress endpoint)248     public void bind(LocalSocketAddress endpoint) throws IOException
249     {
250         if (fd == null) {
251             throw new IOException("socket not created");
252         }
253 
254         bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId());
255     }
256 
listen(int backlog)257     protected void listen(int backlog) throws IOException
258     {
259         if (fd == null) {
260             throw new IOException("socket not created");
261         }
262 
263         listen_native(fd, backlog);
264     }
265 
266     /**
267      * Accepts a new connection to the socket. Blocks until a new
268      * connection arrives.
269      *
270      * @param s a socket that will be used to represent the new connection.
271      * @throws IOException
272      */
accept(LocalSocketImpl s)273     protected void accept(LocalSocketImpl s) throws IOException
274     {
275         if (fd == null) {
276             throw new IOException("socket not created");
277         }
278 
279         s.fd = accept(fd, s);
280     }
281 
282     /**
283      * Retrieves the input stream for this instance.
284      *
285      * @return input stream
286      * @throws IOException if socket has been closed or cannot be created.
287      */
getInputStream()288     protected InputStream getInputStream() throws IOException
289     {
290         if (fd == null) {
291             throw new IOException("socket not created");
292         }
293 
294         synchronized (this) {
295             if (fis == null) {
296                 fis = new SocketInputStream();
297             }
298 
299             return fis;
300         }
301     }
302 
303     /**
304      * Retrieves the output stream for this instance.
305      *
306      * @return output stream
307      * @throws IOException if socket has been closed or cannot be created.
308      */
getOutputStream()309     protected OutputStream getOutputStream() throws IOException
310     {
311         if (fd == null) {
312             throw new IOException("socket not created");
313         }
314 
315         synchronized (this) {
316             if (fos == null) {
317                 fos = new SocketOutputStream();
318             }
319 
320             return fos;
321         }
322     }
323 
324     /**
325      * Returns the number of bytes available for reading without blocking.
326      *
327      * @return >= 0 count bytes available
328      * @throws IOException
329      */
available()330     protected int available() throws IOException
331     {
332         return getInputStream().available();
333     }
334 
335     /**
336      * Shuts down the input side of the socket.
337      *
338      * @throws IOException
339      */
shutdownInput()340     protected void shutdownInput() throws IOException
341     {
342         if (fd == null) {
343             throw new IOException("socket not created");
344         }
345 
346         shutdown(fd, true);
347     }
348 
349     /**
350      * Shuts down the output side of the socket.
351      *
352      * @throws IOException
353      */
shutdownOutput()354     protected void shutdownOutput() throws IOException
355     {
356         if (fd == null) {
357             throw new IOException("socket not created");
358         }
359 
360         shutdown(fd, false);
361     }
362 
getFileDescriptor()363     protected FileDescriptor getFileDescriptor()
364     {
365         return fd;
366     }
367 
supportsUrgentData()368     protected boolean supportsUrgentData()
369     {
370         return false;
371     }
372 
sendUrgentData(int data)373     protected void sendUrgentData(int data) throws IOException
374     {
375         throw new RuntimeException ("not impled");
376     }
377 
getOption(int optID)378     public Object getOption(int optID) throws IOException
379     {
380         if (fd == null) {
381             throw new IOException("socket not created");
382         }
383 
384         if (optID == SocketOptions.SO_TIMEOUT) {
385             return 0;
386         }
387 
388         int value = getOption_native(fd, optID);
389         switch (optID)
390         {
391             case SocketOptions.SO_RCVBUF:
392             case SocketOptions.SO_SNDBUF:
393                 return value;
394             case SocketOptions.SO_REUSEADDR:
395             default:
396                 return value;
397         }
398     }
399 
setOption(int optID, Object value)400     public void setOption(int optID, Object value)
401             throws IOException {
402         /*
403          * Boolean.FALSE is used to disable some options, so it
404          * is important to distinguish between FALSE and unset.
405          * We define it here that -1 is unset, 0 is FALSE, and 1
406          * is TRUE.
407          */
408         int boolValue = -1;
409         int intValue = 0;
410 
411         if (fd == null) {
412             throw new IOException("socket not created");
413         }
414 
415         if (value instanceof Integer) {
416             intValue = (Integer)value;
417         } else if (value instanceof Boolean) {
418             boolValue = ((Boolean) value)? 1 : 0;
419         } else {
420             throw new IOException("bad value: " + value);
421         }
422 
423         setOption_native(fd, optID, boolValue, intValue);
424     }
425 
426     /**
427      * Enqueues a set of file descriptors to send to the peer. The queue
428      * is one deep. The file descriptors will be sent with the next write
429      * of normal data, and will be delivered in a single ancillary message.
430      * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
431      *
432      * @param fds non-null; file descriptors to send.
433      * @throws IOException
434      */
setFileDescriptorsForSend(FileDescriptor[] fds)435     public void setFileDescriptorsForSend(FileDescriptor[] fds) {
436         synchronized(writeMonitor) {
437             outboundFileDescriptors = fds;
438         }
439     }
440 
441     /**
442      * Retrieves a set of file descriptors that a peer has sent through
443      * an ancillary message. This method retrieves the most recent set sent,
444      * and then returns null until a new set arrives.
445      * File descriptors may only be passed along with regular data, so this
446      * method can only return a non-null after a read operation.
447      *
448      * @return null or file descriptor array
449      * @throws IOException
450      */
getAncillaryFileDescriptors()451     public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
452         synchronized(readMonitor) {
453             FileDescriptor[] result = inboundFileDescriptors;
454 
455             inboundFileDescriptors = null;
456             return result;
457         }
458     }
459 
460     /**
461      * Retrieves the credentials of this socket's peer. Only valid on
462      * connected sockets.
463      *
464      * @return non-null; peer credentials
465      * @throws IOException
466      */
getPeerCredentials()467     public Credentials getPeerCredentials() throws IOException
468     {
469         return getPeerCredentials_native(fd);
470     }
471 
472     /**
473      * Retrieves the socket name from the OS.
474      *
475      * @return non-null; socket name
476      * @throws IOException on failure
477      */
getSockAddress()478     public LocalSocketAddress getSockAddress() throws IOException
479     {
480         return null;
481         //TODO implement this
482         //return getSockName_native(fd);
483     }
484 
485     @Override
finalize()486     protected void finalize() throws IOException {
487         close();
488     }
489 }
490 
491