summaryrefslogtreecommitdiffstats
path: root/core/java/android/net/LocalSocketImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/net/LocalSocketImpl.java')
-rw-r--r--core/java/android/net/LocalSocketImpl.java490
1 files changed, 490 insertions, 0 deletions
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
new file mode 100644
index 0000000..6c36a7d
--- /dev/null
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.FileDescriptor;
+import java.net.SocketOptions;
+
+/**
+ * Socket implementation used for android.net.LocalSocket and
+ * android.net.LocalServerSocket. Supports only AF_LOCAL sockets.
+ */
+class LocalSocketImpl
+{
+ private SocketInputStream fis;
+ private SocketOutputStream fos;
+ private Object readMonitor = new Object();
+ private Object writeMonitor = new Object();
+
+ /** null if closed or not yet created */
+ private FileDescriptor fd;
+
+ // These fields are accessed by native code;
+ /** file descriptor array received during a previous read */
+ FileDescriptor[] inboundFileDescriptors;
+ /** file descriptor array that should be written during next write */
+ FileDescriptor[] outboundFileDescriptors;
+
+ /**
+ * An input stream for local sockets. Needed because we may
+ * need to read ancillary data.
+ */
+ class SocketInputStream extends InputStream {
+ /** {@inheritDoc} */
+ @Override
+ public int available() throws IOException {
+ return available_native(fd);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close() throws IOException {
+ LocalSocketImpl.this.close();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read() throws IOException {
+ int ret;
+ synchronized (readMonitor) {
+ FileDescriptor myFd = fd;
+ if (myFd == null) throw new IOException("socket closed");
+
+ ret = read_native(myFd);
+ return ret;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ synchronized (readMonitor) {
+ FileDescriptor myFd = fd;
+ if (myFd == null) throw new IOException("socket closed");
+
+ if (off < 0 || len < 0 || (off + len) > b.length ) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ int ret = readba_native(b, off, len, myFd);
+
+ return ret;
+ }
+ }
+ }
+
+ /**
+ * An output stream for local sockets. Needed because we may
+ * need to read ancillary data.
+ */
+ class SocketOutputStream extends OutputStream {
+ /** {@inheritDoc} */
+ @Override
+ public void close() throws IOException {
+ LocalSocketImpl.this.close();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write (byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write (byte[] b, int off, int len) throws IOException {
+ synchronized (writeMonitor) {
+ FileDescriptor myFd = fd;
+ if (myFd == null) throw new IOException("socket closed");
+
+ if (off < 0 || len < 0 || (off + len) > b.length ) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ writeba_native(b, off, len, myFd);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write (int b) throws IOException {
+ synchronized (writeMonitor) {
+ FileDescriptor myFd = fd;
+ if (myFd == null) throw new IOException("socket closed");
+ write_native(b, myFd);
+ }
+ }
+ }
+
+ private native int available_native(FileDescriptor fd) throws IOException;
+ private native void close_native(FileDescriptor fd) throws IOException;
+ private native int read_native(FileDescriptor fd) throws IOException;
+ private native int readba_native(byte[] b, int off, int len,
+ FileDescriptor fd) throws IOException;
+ private native void writeba_native(byte[] b, int off, int len,
+ FileDescriptor fd) throws IOException;
+ private native void write_native(int b, FileDescriptor fd)
+ throws IOException;
+ private native void connectLocal(FileDescriptor fd, String name,
+ int namespace) throws IOException;
+ private native void bindLocal(FileDescriptor fd, String name, int namespace)
+ throws IOException;
+ private native FileDescriptor create_native(boolean stream)
+ throws IOException;
+ private native void listen_native(FileDescriptor fd, int backlog)
+ throws IOException;
+ private native void shutdown(FileDescriptor fd, boolean shutdownInput);
+ private native Credentials getPeerCredentials_native(
+ FileDescriptor fd) throws IOException;
+ private native int getOption_native(FileDescriptor fd, int optID)
+ throws IOException;
+ private native void setOption_native(FileDescriptor fd, int optID,
+ int b, int value) throws IOException;
+
+// private native LocalSocketAddress getSockName_native
+// (FileDescriptor fd) throws IOException;
+
+ /**
+ * Accepts a connection on a server socket.
+ *
+ * @param fd file descriptor of server socket
+ * @param s socket implementation that will become the new socket
+ * @return file descriptor of new socket
+ */
+ private native FileDescriptor accept
+ (FileDescriptor fd, LocalSocketImpl s) throws IOException;
+
+ /**
+ * Create a new instance.
+ */
+ /*package*/ LocalSocketImpl()
+ {
+ }
+
+ /**
+ * Create a new instance from a file descriptor representing
+ * a bound socket. The state of the file descriptor is not checked here
+ * but the caller can verify socket state by calling listen().
+ *
+ * @param fd non-null; bound file descriptor
+ */
+ /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
+ {
+ this.fd = fd;
+ }
+
+ public String toString() {
+ return super.toString() + " fd:" + fd;
+ }
+
+ /**
+ * Creates a socket in the underlying OS.
+ *
+ * @param stream true if this should be a stream socket, false for
+ * datagram.
+ * @throws IOException
+ */
+ public void create (boolean stream) throws IOException {
+ // no error if socket already created
+ // need this for LocalServerSocket.accept()
+ if (fd == null) {
+ fd = create_native(stream);
+ }
+ }
+
+ /**
+ * Closes the socket.
+ *
+ * @throws IOException
+ */
+ public void close() throws IOException {
+ synchronized (LocalSocketImpl.this) {
+ if (fd == null) return;
+ close_native(fd);
+ fd = null;
+ }
+ }
+
+ /** note timeout presently ignored */
+ protected void connect(LocalSocketAddress address, int timeout)
+ throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ connectLocal(fd, address.getName(), address.getNamespace().getId());
+ }
+
+ /**
+ * Binds this socket to an endpoint name. May only be called on an instance
+ * that has not yet been bound.
+ *
+ * @param endpoint endpoint address
+ * @throws IOException
+ */
+ public void bind(LocalSocketAddress endpoint) throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId());
+ }
+
+ protected void listen(int backlog) throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ listen_native(fd, backlog);
+ }
+
+ /**
+ * Accepts a new connection to the socket. Blocks until a new
+ * connection arrives.
+ *
+ * @param s a socket that will be used to represent the new connection.
+ * @throws IOException
+ */
+ protected void accept(LocalSocketImpl s) throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ s.fd = accept(fd, s);
+ }
+
+ /**
+ * Retrieves the input stream for this instance.
+ *
+ * @return input stream
+ * @throws IOException if socket has been closed or cannot be created.
+ */
+ protected InputStream getInputStream() throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ synchronized (this) {
+ if (fis == null) {
+ fis = new SocketInputStream();
+ }
+
+ return fis;
+ }
+ }
+
+ /**
+ * Retrieves the output stream for this instance.
+ *
+ * @return output stream
+ * @throws IOException if socket has been closed or cannot be created.
+ */
+ protected OutputStream getOutputStream() throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ synchronized (this) {
+ if (fos == null) {
+ fos = new SocketOutputStream();
+ }
+
+ return fos;
+ }
+ }
+
+ /**
+ * Returns the number of bytes available for reading without blocking.
+ *
+ * @return >= 0 count bytes available
+ * @throws IOException
+ */
+ protected int available() throws IOException
+ {
+ return getInputStream().available();
+ }
+
+ /**
+ * Shuts down the input side of the socket.
+ *
+ * @throws IOException
+ */
+ protected void shutdownInput() throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ shutdown(fd, true);
+ }
+
+ /**
+ * Shuts down the output side of the socket.
+ *
+ * @throws IOException
+ */
+ protected void shutdownOutput() throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ shutdown(fd, false);
+ }
+
+ protected FileDescriptor getFileDescriptor()
+ {
+ return fd;
+ }
+
+ protected boolean supportsUrgentData()
+ {
+ return false;
+ }
+
+ protected void sendUrgentData(int data) throws IOException
+ {
+ throw new RuntimeException ("not impled");
+ }
+
+ public Object getOption(int optID) throws IOException
+ {
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ if (optID == SocketOptions.SO_TIMEOUT) {
+ return 0;
+ }
+
+ int value = getOption_native(fd, optID);
+ switch (optID)
+ {
+ case SocketOptions.SO_RCVBUF:
+ case SocketOptions.SO_SNDBUF:
+ return value;
+ case SocketOptions.SO_REUSEADDR:
+ default:
+ return value;
+ }
+ }
+
+ public void setOption(int optID, Object value)
+ throws IOException {
+ /*
+ * Boolean.FALSE is used to disable some options, so it
+ * is important to distinguish between FALSE and unset.
+ * We define it here that -1 is unset, 0 is FALSE, and 1
+ * is TRUE.
+ */
+ int boolValue = -1;
+ int intValue = 0;
+
+ if (fd == null) {
+ throw new IOException("socket not created");
+ }
+
+ if (value instanceof Integer) {
+ intValue = (Integer)value;
+ } else if (value instanceof Boolean) {
+ boolValue = ((Boolean) value)? 1 : 0;
+ } else {
+ throw new IOException("bad value: " + value);
+ }
+
+ setOption_native(fd, optID, boolValue, intValue);
+ }
+
+ /**
+ * Enqueues a set of file descriptors to send to the peer. The queue
+ * is one deep. The file descriptors will be sent with the next write
+ * of normal data, and will be delivered in a single ancillary message.
+ * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine.
+ *
+ * @param fds non-null; file descriptors to send.
+ * @throws IOException
+ */
+ public void setFileDescriptorsForSend(FileDescriptor[] fds) {
+ synchronized(writeMonitor) {
+ outboundFileDescriptors = fds;
+ }
+ }
+
+ /**
+ * Retrieves a set of file descriptors that a peer has sent through
+ * an ancillary message. This method retrieves the most recent set sent,
+ * and then returns null until a new set arrives.
+ * File descriptors may only be passed along with regular data, so this
+ * method can only return a non-null after a read operation.
+ *
+ * @return null or file descriptor array
+ * @throws IOException
+ */
+ public FileDescriptor[] getAncillaryFileDescriptors() throws IOException {
+ synchronized(readMonitor) {
+ FileDescriptor[] result = inboundFileDescriptors;
+
+ inboundFileDescriptors = null;
+ return result;
+ }
+ }
+
+ /**
+ * Retrieves the credentials of this socket's peer. Only valid on
+ * connected sockets.
+ *
+ * @return non-null; peer credentials
+ * @throws IOException
+ */
+ public Credentials getPeerCredentials() throws IOException
+ {
+ return getPeerCredentials_native(fd);
+ }
+
+ /**
+ * Retrieves the socket name from the OS.
+ *
+ * @return non-null; socket name
+ * @throws IOException on failure
+ */
+ public LocalSocketAddress getSockAddress() throws IOException
+ {
+ return null;
+ //TODO implement this
+ //return getSockName_native(fd);
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+}
+