SSL support for VNC proxy
[invirt/packages/invirt-vnc-client.git] / SocketWrapper.java
diff --git a/SocketWrapper.java b/SocketWrapper.java
new file mode 100644 (file)
index 0000000..2920732
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Written by Dawid Kurzyniec and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+
+//package edu.emory.mathcs.util.net;
+
+import java.io.*;
+import java.net.*;
+import java.nio.channels.*;
+
+/**
+ * Wrapper for sockets which enables to add functionality in subclasses
+ * on top of existing, connected sockets. It is useful when direct subclassing
+ * of delegate socket class is not possible, e.g. if the delegate socket is
+ * created by a library. Possible usage example is socket factory chaining.
+ * This class delegates all socket-related requests to the wrapped delegate,
+ * as of JDK 1.4.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.4
+ */
+public abstract class SocketWrapper extends Socket {
+
+    /**
+     * the wrapped delegate socket.
+     */
+    protected final Socket delegate;
+
+    /**
+     * Creates new socket wrapper for a given socket. The delegate
+     * must be connected and bound and it must not be closed.
+     * @param delegate the delegate socket to wrap
+     * @throws SocketException if the delegate socket is closed, not bound,
+     *                         or not connected
+     */
+    protected SocketWrapper(Socket delegate) throws SocketException {
+        super(new WrappingSocketImpl(delegate));
+        this.delegate = delegate;
+    }
+
+    public SocketChannel getChannel() {
+        return delegate.getChannel();
+    }
+
+    /**
+     * Returns true, indicating that the socket is bound.
+     *
+     * @return true
+     */
+    public boolean isBound() {
+        return true;
+    }
+
+    public boolean isClosed() {
+        return super.isClosed() || delegate.isClosed();
+    }
+
+    /**
+     * Returns true, indicating that the socket is connected.
+     *
+     * @return true
+     */
+    public boolean isConnected() {
+        return true;
+    }
+
+    public boolean isInputShutdown() {
+        return super.isInputShutdown() || delegate.isInputShutdown();
+    }
+
+    public boolean isOutputShutdown() {
+        return super.isInputShutdown() || delegate.isOutputShutdown();
+    }
+
+    private static class WrappingSocketImpl extends SocketImpl {
+        private final Socket delegate;
+        WrappingSocketImpl(Socket delegate) throws SocketException {
+            if (delegate == null) {
+                throw new NullPointerException();
+            }
+            if (delegate.isClosed()) {
+                throw new SocketException("Delegate server socket is closed");
+            }
+            if (!(delegate.isBound())) {
+                throw new SocketException("Delegate server socket is not bound");
+            }
+            if (!(delegate.isConnected())) {
+                throw new SocketException("Delegate server socket is not connected");
+            }
+            this.delegate = delegate;
+        }
+
+        protected void create(boolean stream) {}
+
+        protected void connect(String host, int port) {
+            // delegate is always connected, thus this method is never called
+            throw new UnsupportedOperationException();
+        }
+
+        protected void connect(InetAddress address, int port) {
+            // delegate is always connected, thus this method is never called
+            throw new UnsupportedOperationException();
+        }
+
+        protected void connect(SocketAddress address, int timeout) {
+            // delegate is always connected, thus this method is never called
+            throw new UnsupportedOperationException();
+        }
+
+        protected void bind(InetAddress host, int port) {
+            // delegate is always bound, thus this method is never called
+            throw new UnsupportedOperationException();
+        }
+
+        protected void listen(int backlog) {
+            // this wrapper is never used by a ServerSocket
+            throw new UnsupportedOperationException();
+        }
+
+        protected void accept(SocketImpl s) {
+            // this wrapper is never used by a ServerSocket
+            throw new UnsupportedOperationException();
+        }
+
+        protected InputStream getInputStream() throws IOException {
+            return delegate.getInputStream();
+        }
+
+        protected OutputStream getOutputStream() throws IOException {
+            return delegate.getOutputStream();
+        }
+
+        protected int available() throws IOException {
+            return getInputStream().available();
+        }
+
+        protected void close() throws IOException {
+            delegate.close();
+        }
+
+        protected void shutdownInput() throws IOException {
+            delegate.shutdownInput();
+        }
+
+        protected void shutdownOutput() throws IOException {
+            delegate.shutdownOutput();
+        }
+
+        protected FileDescriptor getFileDescriptor() {
+            // this wrapper is never used by a ServerSocket
+            throw new UnsupportedOperationException();
+        }
+
+        protected InetAddress getInetAddress() {
+            return delegate.getInetAddress();
+        }
+
+        protected int getPort() {
+            return delegate.getPort();
+        }
+
+        protected boolean supportsUrgentData() {
+            return false; // must be overridden in sub-class
+        }
+
+        protected void sendUrgentData (int data) throws IOException {
+            delegate.sendUrgentData(data);
+        }
+
+        protected int getLocalPort() {
+            return delegate.getLocalPort();
+        }
+
+        public Object getOption(int optID) throws SocketException {
+            switch (optID) {
+                case SocketOptions.IP_TOS:
+                    return new Integer(delegate.getTrafficClass());
+                case SocketOptions.SO_BINDADDR:
+                    return delegate.getLocalAddress();
+                case SocketOptions.SO_KEEPALIVE:
+                    return Boolean.valueOf(delegate.getKeepAlive());
+                case SocketOptions.SO_LINGER:
+                    return new Integer(delegate.getSoLinger());
+                case SocketOptions.SO_OOBINLINE:
+                    return Boolean.valueOf(delegate.getOOBInline());
+                case SocketOptions.SO_RCVBUF:
+                    return new Integer(delegate.getReceiveBufferSize());
+                case SocketOptions.SO_REUSEADDR:
+                    return Boolean.valueOf(delegate.getReuseAddress());
+                case SocketOptions.SO_SNDBUF:
+                    return new Integer(delegate.getSendBufferSize());
+                case SocketOptions.SO_TIMEOUT:
+                    return new Integer(delegate.getSoTimeout());
+                case SocketOptions.TCP_NODELAY:
+                    return Boolean.valueOf(delegate.getTcpNoDelay());
+                case SocketOptions.SO_BROADCAST:
+                default:
+                    throw new IllegalArgumentException("Unsupported option type");
+            }
+        }
+
+        public void setOption(int optID, Object value) throws SocketException {
+            switch (optID) {
+                case SocketOptions.SO_BINDADDR:
+                    throw new IllegalArgumentException("Socket is bound");
+                case SocketOptions.SO_KEEPALIVE:
+                    delegate.setKeepAlive(((Boolean)value).booleanValue());
+                    break;
+                case SocketOptions.SO_LINGER:
+                    if (value instanceof Boolean) {
+                        delegate.setSoLinger(((Boolean)value).booleanValue(), 0);
+                    }
+                    else {
+                        delegate.setSoLinger(true, ((Integer)value).intValue());
+                    }
+                    break;
+                case SocketOptions.SO_OOBINLINE:
+                    delegate.setOOBInline(((Boolean)value).booleanValue());
+                    break;
+                case SocketOptions.SO_RCVBUF:
+                    delegate.setReceiveBufferSize(((Integer)value).intValue());
+                    break;
+                case SocketOptions.SO_REUSEADDR:
+                    delegate.setReuseAddress(((Boolean)value).booleanValue());
+                    break;
+                case SocketOptions.SO_SNDBUF:
+                    delegate.setSendBufferSize(((Integer)value).intValue());
+                    break;
+                case SocketOptions.SO_TIMEOUT:
+                    delegate.setSoTimeout(((Integer)value).intValue());
+                    break;
+                case SocketOptions.TCP_NODELAY:
+                    delegate.setTcpNoDelay(((Boolean)value).booleanValue());
+                    break;
+                case SocketOptions.SO_BROADCAST:
+                default:
+                    throw new IllegalArgumentException("Unsupported option type");
+            }
+        }
+    }
+
+    public boolean equals(Object obj) {
+        if (!(obj instanceof SocketWrapper)) return false;
+        SocketWrapper that = (SocketWrapper)obj;
+        return this.delegate.equals(that.delegate);
+    }
+
+    public int hashCode() {
+        return delegate.hashCode() ^ 0x01010101;
+    }
+}
\ No newline at end of file