aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/unix
diff options
context:
space:
mode:
authorGravatar Janak Ramakrishnan <janakr@google.com>2016-08-11 20:46:20 +0000
committerGravatar Yue Gan <yueg@google.com>2016-08-12 08:52:58 +0000
commitbab0d481dea8be7568cd593460c26111bf302175 (patch)
tree30b454482bcded54cf216b30fa40a98d56fa679a /src/main/java/com/google/devtools/build/lib/unix
parent7e33704e7546bb676e9052089c30f1dd625fd082 (diff)
Rollback of commit f107debac45ddf5859b1eb963379769b5815b18f. Also includes the logical rollback of commit 67ad82a319ff8959e69e774e7c15d3af904ec23d.
RELNOTES[INC]: Bazel supports Unix domain sockets for communication between its client and server again, temporarily, while we diagnose a memory leak. -- MOS_MIGRATED_REVID=130027009
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/unix')
-rw-r--r--src/main/java/com/google/devtools/build/lib/unix/LocalClientSocket.java117
-rw-r--r--src/main/java/com/google/devtools/build/lib/unix/LocalServerSocket.java173
-rw-r--r--src/main/java/com/google/devtools/build/lib/unix/LocalSocket.java216
-rw-r--r--src/main/java/com/google/devtools/build/lib/unix/LocalSocketAddress.java56
-rw-r--r--src/main/java/com/google/devtools/build/lib/unix/LocalSocketImpl.java171
5 files changed, 733 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/unix/LocalClientSocket.java b/src/main/java/com/google/devtools/build/lib/unix/LocalClientSocket.java
new file mode 100644
index 0000000000..10335d1a93
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/unix/LocalClientSocket.java
@@ -0,0 +1,117 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.lib.unix;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketException;
+
+/**
+ * <p>An implementation of client Socket for local (AF_UNIX) sockets.
+ *
+ * <p>This class intentionally doesn't extend java.net.Socket although it
+ * has some similarity to it. The java.net class hierarchy is a terrible mess
+ * and is inextricably coupled to the Internet Protocol.
+ *
+ * <p>This code is not intended to be portable to non-UNIX platforms.
+ */
+public class LocalClientSocket extends LocalSocket {
+
+ /**
+ * Constructs an unconnected local client socket.
+ *
+ * @throws IOException if the socket could not be created.
+ */
+ public LocalClientSocket() throws IOException {
+ super();
+ }
+
+ /**
+ * Constructs a client socket and connects it to the specified address.
+ *
+ * @throws IOException if either of the socket/connect operations failed.
+ */
+ public LocalClientSocket(LocalSocketAddress address) throws IOException {
+ super();
+ connect(address);
+ }
+
+ /**
+ * Connect to the specified server. Blocks until the server accepts the
+ * connection.
+ *
+ * @throws IOException if the connection failed.
+ */
+ public synchronized void connect(LocalSocketAddress address)
+ throws IOException {
+ checkNotClosed();
+ if (state == State.CONNECTED) {
+ throw new SocketException("socket is already connected");
+ }
+ connect(fd, address.getName().toString()); // JNI
+ this.address = address;
+ this.state = State.CONNECTED;
+ }
+
+ /**
+ * Returns the input stream for reading from the server.
+ *
+ * @param closeSocket close the socket when this input stream is closed.
+ * @throws IOException if there was a problem.
+ */
+ public synchronized InputStream getInputStream(final boolean closeSocket) throws IOException {
+ checkConnected();
+ checkInputNotShutdown();
+ return new FileInputStream(fd) {
+ @Override
+ public void close() throws IOException {
+ if (closeSocket) {
+ LocalClientSocket.this.close();
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns the input stream for reading from the server.
+ *
+ * @throws IOException if there was a problem.
+ */
+ public synchronized InputStream getInputStream() throws IOException {
+ return getInputStream(false);
+ }
+
+ /**
+ * Returns the output stream for writing to the server.
+ *
+ * @throws IOException if there was a problem.
+ */
+ public synchronized OutputStream getOutputStream() throws IOException {
+ checkConnected();
+ checkOutputNotShutdown();
+ return new FileOutputStream(fd) {
+ @Override public void close() {
+ // Don't close the file descriptor.
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ return "LocalClientSocket(" + address + ")";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/unix/LocalServerSocket.java b/src/main/java/com/google/devtools/build/lib/unix/LocalServerSocket.java
new file mode 100644
index 0000000000..0c0bd22c3f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/unix/LocalServerSocket.java
@@ -0,0 +1,173 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.lib.unix;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+
+/**
+ * <p>An implementation of ServerSocket for local (AF_UNIX) sockets.
+ *
+ * <p>This class intentionally doesn't extend java.net.ServerSocket although it
+ * has some similarity to it. The java.net class hierarchy is a terrible mess
+ * and is inextricably coupled to the Internet Protocol.
+ *
+ * <p>This code is not intended to be portable to non-UNIX platforms.
+ */
+public class LocalServerSocket extends LocalSocket {
+
+ // Socket timeout in milliseconds. No timeout by default.
+ private long soTimeoutMillis = 0;
+
+ /**
+ * Constructs an unbound local server socket.
+ */
+ public LocalServerSocket() throws IOException {
+ super();
+ }
+
+ /**
+ * Constructs a server socket, binds it to the specified address, and
+ * listens for incoming connections with the specified backlog.
+ *
+ * @throws IOException if any of the socket/bind/listen operations failed.
+ */
+ public LocalServerSocket(LocalSocketAddress address, int backlog)
+ throws IOException {
+ this();
+ bind(address);
+ listen(backlog);
+ }
+
+ /**
+ * Constructs a server socket, binds it to the specified address, and begin
+ * listening for incoming connections using the default backlog.
+ *
+ * @throws IOException if any of the socket/bind/listen operations failed.
+ */
+ public LocalServerSocket(LocalSocketAddress address) throws IOException {
+ this(address, 50);
+ }
+
+ /**
+ * Specifies the timeout in milliseconds for accept(). Setting it to
+ * zero means an indefinite timeout.
+ */
+ public void setSoTimeout(long timeoutMillis) {
+ soTimeoutMillis = timeoutMillis;
+ }
+
+ /**
+ * Returns the current timeout in milliseconds.
+ */
+ public long getSoTimeout() {
+ return soTimeoutMillis;
+ }
+
+ /**
+ * Binds the specified address to this socket. The socket must be unbound.
+ * This causes the filesystem entry to appear.
+ *
+ * @throws IOException if the bind failed.
+ */
+ public synchronized void bind(LocalSocketAddress address)
+ throws IOException {
+ if (address == null) {
+ throw new NullPointerException("address");
+ }
+ checkNotClosed();
+ if (state != State.NEW) {
+ throw new SocketException("socket is already bound to an address");
+ }
+ bind(fd, address.getName().toString()); // JNI
+ this.address = address;
+ this.state = State.BOUND;
+ }
+
+ /**
+ * Listen for incoming connections on a socket using the specfied backlog.
+ * The socket must be bound but not already listening.
+ *
+ * @throws IOException if the listen failed.
+ */
+ public synchronized void listen(int backlog) throws IOException {
+ if (backlog < 1) {
+ throw new IllegalArgumentException("backlog=" + backlog);
+ }
+ checkNotClosed();
+ if (address == null) {
+ throw new SocketException("socket has no address bound");
+ }
+ if (state == State.LISTENING) {
+ throw new SocketException("socket is already listening");
+ }
+ listen(fd, backlog); // JNI
+ this.state = State.LISTENING;
+ }
+
+ /**
+ * Blocks until a connection is made to this socket and accepts it, returning
+ * a new socket connected to the client.
+ *
+ * @return the new socket connected to the client.
+ * @throws IOException if an error occurs when waiting for a connection.
+ * @throws SocketTimeoutException if a timeout was previously set with
+ * setSoTimeout and the timeout has been reached.
+ * @throws InterruptedIOException if the thread is interrupted when the
+ * method is blocked.
+ */
+ public synchronized Socket accept()
+ throws IOException, SocketTimeoutException, InterruptedIOException {
+ if (state != State.LISTENING) {
+ throw new SocketException("socket is not in listening state");
+ }
+
+ // Throws a SocketTimeoutException if timeout.
+ if (soTimeoutMillis != 0) {
+ poll(fd, soTimeoutMillis); // JNI
+ }
+
+ FileDescriptor clientFd = new FileDescriptor();
+ accept(fd, clientFd); // JNI
+ final LocalSocketImpl impl = new LocalSocketImpl(clientFd);
+ return new Socket(impl) {
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+ @Override
+ public synchronized void close() throws IOException {
+ if (isClosed()) {
+ return;
+ } else {
+ super.close();
+ // Workaround for the fact that super.created==false because we
+ // created the impl ourselves. As a result, super.close() doesn't
+ // call impl.close(). *Sigh*, java.net is horrendous.
+ // (Perhaps we should dispense with Socket/SocketImpl altogether?)
+ impl.close();
+ }
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ return "LocalServerSocket(" + address + ")";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/unix/LocalSocket.java b/src/main/java/com/google/devtools/build/lib/unix/LocalSocket.java
new file mode 100644
index 0000000000..d51f2bad36
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/unix/LocalSocket.java
@@ -0,0 +1,216 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.lib.unix;
+
+import com.google.devtools.build.lib.UnixJniLoader;
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+
+/**
+ * Abstract superclass for client and server local sockets.
+ */
+abstract class LocalSocket implements Closeable {
+
+ protected enum State {
+ NEW,
+ BOUND, // server only
+ LISTENING, // server only
+ CONNECTED, // client only
+ CLOSED,
+ }
+
+ protected LocalSocketAddress address = null;
+ protected FileDescriptor fd = new FileDescriptor();
+ protected State state;
+ protected boolean inputShutdown = false;
+ protected boolean outputShutdown = false;
+
+ /**
+ * Constructs an unconnected local socket.
+ */
+ protected LocalSocket() throws IOException {
+ socket(fd);
+ if (!fd.valid()) {
+ throw new IOException("Couldn't create socket!");
+ }
+ this.state = State.NEW;
+ }
+
+ /**
+ * Returns the address of the endpoint this socket is bound to.
+ *
+ * @return a <code>SocketAddress</code> representing the local endpoint of
+ * this socket.
+ */
+ public LocalSocketAddress getLocalSocketAddress() {
+ return address;
+ }
+
+ /**
+ * Closes this socket. This operation is idempotent.
+ *
+ * To be consistent with Java Socket, the shutdown states of the socket are
+ * not changed. This makes it easier to port applications between Socket and
+ * LocalSocket.
+ *
+ * @throws IOException if an I/O error occurred when closing the socket.
+ */
+ @Override
+ public synchronized void close() throws IOException {
+ if (state == State.CLOSED) {
+ return;
+ }
+ // Closes the file descriptor if it has not been closed by the
+ // input/output streams.
+ if (!fd.valid()) {
+ throw new IllegalStateException("LocalSocket.close(-1)");
+ }
+ close(fd);
+ if (fd.valid()) {
+ throw new IllegalStateException("LocalSocket.close() did not set fd to -1");
+ }
+ this.state = State.CLOSED;
+ }
+
+ /**
+ * Returns the closed state of the ServerSocket.
+ *
+ * @return true if the socket has been closed
+ */
+ public synchronized boolean isClosed() {
+ // If the file descriptor has been closed by the input/output
+ // streams, marks the socket as closed too.
+ return state == State.CLOSED;
+ }
+
+ /**
+ * Returns the connected state of the ClientSocket.
+ *
+ * @return true if the socket is currently connected.
+ */
+ public synchronized boolean isConnected() {
+ return state == State.CONNECTED;
+ }
+
+ protected synchronized void checkConnected() throws SocketException {
+ if (!isConnected()) {
+ throw new SocketException("Transport endpoint is not connected");
+ }
+ }
+
+ protected synchronized void checkNotClosed() throws SocketException {
+ if (isClosed()) {
+ throw new SocketException("socket is closed");
+ }
+ }
+
+ /**
+ * Returns the shutdown state of the input channel.
+ *
+ * @return true is the input channel of the socket is shutdown.
+ */
+ public synchronized boolean isInputShutdown() {
+ return inputShutdown;
+ }
+
+ /**
+ * Returns the shutdown state of the output channel.
+ *
+ * @return true is the input channel of the socket is shutdown.
+ */
+ public synchronized boolean isOutputShutdown() {
+ return outputShutdown;
+ }
+
+ protected synchronized void checkInputNotShutdown() throws SocketException {
+ if (isInputShutdown()) {
+ throw new SocketException("Socket input is shutdown");
+ }
+ }
+
+ protected synchronized void checkOutputNotShutdown() throws SocketException {
+ if (isOutputShutdown()) {
+ throw new SocketException("Socket output is shutdown");
+ }
+ }
+
+ static final int SHUT_RD = 0; // Mapped to BSD SHUT_RD in JNI.
+ static final int SHUT_WR = 1; // Mapped to BSD SHUT_WR in JNI.
+
+ public synchronized void shutdownInput() throws IOException {
+ checkNotClosed();
+ checkConnected();
+ checkInputNotShutdown();
+ inputShutdown = true;
+ shutdown(fd, SHUT_RD);
+ }
+
+ public synchronized void shutdownOutput() throws IOException {
+ checkNotClosed();
+ checkConnected();
+ checkOutputNotShutdown();
+ outputShutdown = true;
+ shutdown(fd, SHUT_WR);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // JNI:
+
+ static {
+ UnixJniLoader.loadJni();
+ }
+
+ // The native calls below are thin wrappers around linux system calls. The
+ // semantics remains the same except for poll(). See the comments for the
+ // method.
+ //
+ // Note: FileDescriptor is a box for a mutable integer that is visible only
+ // to native code.
+
+ // Generic operations:
+ protected static native void socket(FileDescriptor server)
+ throws IOException;
+ static native void close(FileDescriptor server)
+ throws IOException;
+ /**
+ * Shut down part of a full-duplex connection
+ * @param code Must be either SHUT_RD or SHUT_WR
+ */
+ static native void shutdown(FileDescriptor fd, int code)
+ throws IOException;
+
+ /**
+ * This method checks waits for the given file descriptor to become available for read.
+ * If timeoutMillis passed and there is no activity, a SocketTimeoutException will be thrown.
+ */
+ protected static native void poll(FileDescriptor read, long timeoutMillis)
+ throws IOException, SocketTimeoutException, InterruptedIOException;
+
+ // Server operations:
+ protected static native void bind(FileDescriptor server, String filename)
+ throws IOException;
+ protected static native void listen(FileDescriptor server, int backlog)
+ throws IOException;
+ protected static native void accept(FileDescriptor server,
+ FileDescriptor client)
+ throws IOException;
+
+ // Client operations:
+ protected static native void connect(FileDescriptor client, String filename)
+ throws IOException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/unix/LocalSocketAddress.java b/src/main/java/com/google/devtools/build/lib/unix/LocalSocketAddress.java
new file mode 100644
index 0000000000..f9b9d43f06
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/unix/LocalSocketAddress.java
@@ -0,0 +1,56 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.lib.unix;
+
+import java.io.File;
+import java.net.SocketAddress;
+
+/**
+ * An implementation of SocketAddress for naming local sockets, i.e. files in
+ * the UNIX file system.
+ */
+public class LocalSocketAddress extends SocketAddress {
+
+ private final File name;
+
+ /**
+ * Constructs a SocketAddress for the specified file.
+ */
+ public LocalSocketAddress(File name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the filename of this local socket address.
+ */
+ public File getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof LocalSocketAddress &&
+ ((LocalSocketAddress) other).name.equals(this.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/unix/LocalSocketImpl.java b/src/main/java/com/google/devtools/build/lib/unix/LocalSocketImpl.java
new file mode 100644
index 0000000000..a30b450dc1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/unix/LocalSocketImpl.java
@@ -0,0 +1,171 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.lib.unix;
+
+import com.google.devtools.build.lib.UnixJniLoader;
+import com.google.devtools.build.lib.util.OS;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketImpl;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A simple implementation of SocketImpl for sockets that wrap a UNIX
+ * file-descriptor. This SocketImpl assumes that the socket is already
+ * created, bound, connected and supports no socket options or out-of-band
+ * features. This is used to implement server-side accepted client sockets
+ * (i.e. those returned by {@link LocalServerSocket#accept}).
+ */
+class LocalSocketImpl extends SocketImpl {
+ private static final Logger logger =
+ Logger.getLogger(LocalSocketImpl.class.getName());
+
+ static {
+ UnixJniLoader.loadJni();
+ if (OS.getCurrent() != OS.WINDOWS) {
+ init();
+ }
+ }
+
+ // The logic here is a little twisted, to support JDK7 and JDK8.
+
+ // 1) In JDK7, the FileDescriptor class keeps a reference count of
+ // instances using the fd, and closes it when it goes to 0. The
+ // reference count is only decremented by the finalizer for a
+ // given class. When the call to close() happens, the fd is
+ // closed regardless of the current state of the refcount.
+ //
+ // 2) In JDK8, every instance that uses the fd registers a Closeable
+ // with the FileDescriptor. Since the FileDescriptor has a
+ // reference to every user, only when all of the users and the
+ // FileDescriptor get GC'd does the finalizer run. An explicit
+ // call to close() calls FileDescriptor.closeAll(), which
+ // force-closes all of the users.
+
+ // So, in our case:
+
+ // 1) ref() increments the refcount in JDK7, and registers with the
+ // FD in JDK8.
+
+ // 2) unref() decrements the refcount in JDK7, and does nothing in
+ // JDK8.
+
+ // 3) The finalizer decrements the refcount in JDK7, and simply
+ // calls close() in JDK8 (where we don't have to worry about
+ // multiple live users of the FD). The close() method itself is
+ // idempotent.
+
+ // 4) close() calls fd.closeAll in JDK8, which, in turn, calls
+ // closer.close(). In JDK7, close() calls closer.close()
+ // explicitly.
+ private static native void init();
+ private static native void ref(FileDescriptor fd, Closeable closeable);
+ private static native boolean unref(FileDescriptor fd);
+ private static native boolean close0(FileDescriptor fd, Closeable closeable);
+
+ private final boolean isInitialized;
+ private final Closeable closer = new Closeable() {
+ AtomicBoolean isClosed = new AtomicBoolean(false);
+ @Override public void close() throws IOException {
+ if (isClosed.compareAndSet(false, true)) {
+ LocalSocket.close(fd);
+ }
+ }
+ };
+
+ // Note to callers: if you pass a FD into this constructor, this
+ // instance is now responsible for closing it (in the sense of
+ // LocalSocket.close()). If some other instance tries to close it,
+ // then terrible things will happen.
+ LocalSocketImpl(FileDescriptor fd) {
+ this.fd = fd; // (inherited field)
+ ref(fd, closer);
+ isInitialized = true;
+ }
+
+ @Override protected void finalize() {
+ try {
+ if (isInitialized) {
+ if (!unref(fd)) {
+ // JDK8 codepath
+ close0(fd, closer);
+ }
+ }
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Unable to access FileDescriptor class - " +
+ "may cause a file descriptor leak", e);
+ }
+ }
+ @Override protected InputStream getInputStream() {
+ return new FileInputStream(getFileDescriptor());
+ }
+ @Override protected OutputStream getOutputStream() {
+ return new FileOutputStream(getFileDescriptor());
+ }
+ @Override protected void close() throws IOException {
+ if (fd.valid()) {
+ if (!close0(fd, closer)) {
+ // JDK7 codepath
+ closer.close();
+ }
+ }
+ }
+
+ // Unused:
+ @Override
+ public void setOption(int optID, Object value) {
+ throw new UnsupportedOperationException("setOption");
+ }
+ @Override
+ public Object getOption(int optID) {
+ throw new UnsupportedOperationException("getOption");
+ }
+ @Override protected void create(boolean stream) {
+ throw new UnsupportedOperationException("create");
+ }
+ @Override protected void connect(String host, int port) {
+ throw new UnsupportedOperationException("connect");
+ }
+ @Override protected void connect(InetAddress address, int port) {
+ throw new UnsupportedOperationException("connect2");
+ }
+ @Override protected void connect(SocketAddress address, int timeout) {
+ throw new UnsupportedOperationException("connect3");
+ }
+ @Override protected void bind(InetAddress host, int port) {
+ throw new UnsupportedOperationException("bind");
+ }
+ @Override protected void listen(int backlog) {
+ throw new UnsupportedOperationException("listen");
+ }
+ @Override protected void accept(SocketImpl s) {
+ throw new UnsupportedOperationException("accept");
+ }
+ @Override protected int available() {
+ throw new UnsupportedOperationException("available");
+ }
+ @Override protected void sendUrgentData(int i) {
+ throw new UnsupportedOperationException("sendUrgentData");
+ }
+}