| /* |
| * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| |
| package sun.security.ssl; |
| |
| import java.io.*; |
| import java.nio.channels.SocketChannel; |
| import java.net.*; |
| |
| import javax.net.ssl.*; |
| |
| /** |
| * Abstract base class for SSLSocketImpl. Its purpose is to house code with |
| * no SSL related logic (or no logic at all). This makes SSLSocketImpl shorter |
| * and easier to read. It contains a few constants and static methods plus |
| * overridden java.net.Socket methods. |
| * |
| * Methods are defined final to ensure that they are not accidentally |
| * overridden in SSLSocketImpl. |
| * |
| * @see javax.net.ssl.SSLSocket |
| * @see SSLSocketImpl |
| * |
| */ |
| abstract class BaseSSLSocketImpl extends SSLSocket { |
| |
| /* |
| * Normally "self" is "this" ... but not when this connection is |
| * layered over a preexisting socket. If we're using an existing |
| * socket, we delegate some actions to it. Else, we delegate |
| * instead to "super". This is important to ensure that we don't |
| * recurse infinitely ... e.g. close() calling itself, or doing |
| * I/O in terms of our own streams. |
| */ |
| final Socket self; |
| |
| BaseSSLSocketImpl() { |
| super(); |
| this.self = this; |
| } |
| |
| BaseSSLSocketImpl(Socket socket) { |
| super(); |
| this.self = socket; |
| } |
| |
| // |
| // CONSTANTS AND STATIC METHODS |
| // |
| |
| /** |
| * TLS requires that a close_notify warning alert is sent before the |
| * connection is closed in order to avoid truncation attacks. Some |
| * implementations (MS IIS and others) don't do that. The property |
| * below controls whether we accept that or treat it as an error. |
| * |
| * The default is "false", i.e. tolerate the broken behavior. |
| */ |
| private final static String PROP_NAME = |
| "com.sun.net.ssl.requireCloseNotify"; |
| |
| final static boolean requireCloseNotify = |
| Debug.getBooleanProperty(PROP_NAME, false); |
| |
| // |
| // MISC SOCKET METHODS |
| // |
| |
| /** |
| * Returns the unique {@link java.nio.SocketChannel SocketChannel} object |
| * associated with this socket, if any. |
| * @see java.net.Socket#getChannel |
| */ |
| public final SocketChannel getChannel() { |
| if (self == this) { |
| return super.getChannel(); |
| } else { |
| return self.getChannel(); |
| } |
| } |
| |
| /** |
| * Binds the address to the socket. |
| * @see java.net.Socket#bind |
| */ |
| public void bind(SocketAddress bindpoint) throws IOException { |
| /* |
| * Bind to this socket |
| */ |
| if (self == this) { |
| super.bind(bindpoint); |
| } else { |
| // If we're binding on a layered socket... |
| throw new IOException( |
| "Underlying socket should already be connected"); |
| } |
| } |
| |
| /** |
| * Returns the address of the endpoint this socket is connected to |
| * @see java.net.Socket#getLocalSocketAddress |
| */ |
| public SocketAddress getLocalSocketAddress() { |
| if (self == this) { |
| return super.getLocalSocketAddress(); |
| } else { |
| return self.getLocalSocketAddress(); |
| } |
| } |
| |
| /** |
| * Returns the address of the endpoint this socket is connected to |
| * @see java.net.Socket#getRemoteSocketAddress |
| */ |
| public SocketAddress getRemoteSocketAddress() { |
| if (self == this) { |
| return super.getRemoteSocketAddress(); |
| } else { |
| return self.getRemoteSocketAddress(); |
| } |
| } |
| |
| /** |
| * Connects this socket to the server. |
| * |
| * This method is either called on an unconnected SSLSocketImpl by the |
| * application, or it is called in the constructor of a regular |
| * SSLSocketImpl. If we are layering on top on another socket, then |
| * this method should not be called, because we assume that the |
| * underlying socket is already connected by the time it is passed to |
| * us. |
| * |
| * @param endpoint the <code>SocketAddress</code> |
| * @throws IOException if an error occurs during the connection |
| */ |
| public final void connect(SocketAddress endpoint) throws IOException { |
| connect(endpoint, 0); |
| } |
| |
| /** |
| * Returns the connection state of the socket. |
| * @see java.net.Socket#isConnected |
| */ |
| public final boolean isConnected() { |
| if (self == this) { |
| return super.isConnected(); |
| } else { |
| return self.isConnected(); |
| } |
| } |
| |
| /** |
| * Returns the binding state of the socket. |
| * @see java.net.Socket#isBound |
| */ |
| public final boolean isBound() { |
| if (self == this) { |
| return super.isBound(); |
| } else { |
| return self.isBound(); |
| } |
| } |
| |
| // |
| // CLOSE RELATED METHODS |
| // |
| |
| /** |
| * The semantics of shutdownInput is not supported in TLS 1.0 |
| * spec. Thus when the method is called on an SSL socket, an |
| * UnsupportedOperationException will be thrown. |
| * |
| * @throws UnsupportedOperationException |
| */ |
| public final void shutdownInput() throws IOException { |
| throw new UnsupportedOperationException("The method shutdownInput()" + |
| " is not supported in SSLSocket"); |
| } |
| |
| /** |
| * The semantics of shutdownOutput is not supported in TLS 1.0 |
| * spec. Thus when the method is called on an SSL socket, an |
| * UnsupportedOperationException will be thrown. |
| * |
| * @throws UnsupportedOperationException |
| */ |
| public final void shutdownOutput() throws IOException { |
| throw new UnsupportedOperationException("The method shutdownOutput()" + |
| " is not supported in SSLSocket"); |
| |
| } |
| |
| /** |
| * Returns the input state of the socket |
| * @see java.net.Socket#isInputShutdown |
| */ |
| public final boolean isInputShutdown() { |
| if (self == this) { |
| return super.isInputShutdown(); |
| } else { |
| return self.isInputShutdown(); |
| } |
| } |
| |
| /** |
| * Returns the output state of the socket |
| * @see java.net.Socket#isOutputShutdown |
| */ |
| public final boolean isOutputShutdown() { |
| if (self == this) { |
| return super.isOutputShutdown(); |
| } else { |
| return self.isOutputShutdown(); |
| } |
| } |
| |
| /** |
| * Ensures that the SSL connection is closed down as cleanly |
| * as possible, in case the application forgets to do so. |
| * This allows SSL connections to be implicitly reclaimed, |
| * rather than forcing them to be explicitly reclaimed at |
| * the penalty of prematurly killing SSL sessions. |
| */ |
| protected final void finalize() throws Throwable { |
| try { |
| close(); |
| } catch (IOException e1) { |
| try { |
| if (self == this) { |
| super.close(); |
| } |
| } catch (IOException e2) { |
| // ignore |
| } |
| } finally { |
| // We called close on the underlying socket above to |
| // make doubly sure all resources got released. We |
| // don't finalize self in the case of overlain sockets, |
| // that's a different object which the GC will finalize |
| // separately. |
| |
| super.finalize(); |
| } |
| } |
| |
| // |
| // GET ADDRESS METHODS |
| // |
| |
| /** |
| * Returns the address of the remote peer for this connection. |
| */ |
| public final InetAddress getInetAddress() { |
| if (self == this) { |
| return super.getInetAddress(); |
| } else { |
| return self.getInetAddress(); |
| } |
| } |
| |
| /** |
| * Gets the local address to which the socket is bound. |
| * |
| * @return the local address to which the socket is bound. |
| * @since JDK1.1 |
| */ |
| public final InetAddress getLocalAddress() { |
| if (self == this) { |
| return super.getLocalAddress(); |
| } else { |
| return self.getLocalAddress(); |
| } |
| } |
| |
| /** |
| * Returns the number of the remote port that this connection uses. |
| */ |
| public final int getPort() { |
| if (self == this) { |
| return super.getPort(); |
| } else { |
| return self.getPort(); |
| } |
| } |
| |
| /** |
| * Returns the number of the local port that this connection uses. |
| */ |
| public final int getLocalPort() { |
| if (self == this) { |
| return super.getLocalPort(); |
| } else { |
| return self.getLocalPort(); |
| } |
| } |
| |
| // |
| // SOCKET OPTION METHODS |
| // |
| |
| /** |
| * Enables or disables the Nagle optimization. |
| * @see java.net.Socket#setTcpNoDelay |
| */ |
| public final void setTcpNoDelay(boolean value) throws SocketException { |
| if (self == this) { |
| super.setTcpNoDelay(value); |
| } else { |
| self.setTcpNoDelay(value); |
| } |
| } |
| |
| /** |
| * Returns true if the Nagle optimization is disabled. This |
| * relates to low-level buffering of TCP traffic, delaying the |
| * traffic to promote better throughput. |
| * |
| * @see java.net.Socket#getTcpNoDelay |
| */ |
| public final boolean getTcpNoDelay() throws SocketException { |
| if (self == this) { |
| return super.getTcpNoDelay(); |
| } else { |
| return self.getTcpNoDelay(); |
| } |
| } |
| |
| /** |
| * Assigns the socket's linger timeout. |
| * @see java.net.Socket#setSoLinger |
| */ |
| public final void setSoLinger(boolean flag, int linger) |
| throws SocketException { |
| if (self == this) { |
| super.setSoLinger(flag, linger); |
| } else { |
| self.setSoLinger(flag, linger); |
| } |
| } |
| |
| /** |
| * Returns the socket's linger timeout. |
| * @see java.net.Socket#getSoLinger |
| */ |
| public final int getSoLinger() throws SocketException { |
| if (self == this) { |
| return super.getSoLinger(); |
| } else { |
| return self.getSoLinger(); |
| } |
| } |
| |
| /** |
| * Send one byte of urgent data on the socket. |
| * @see java.net.Socket#sendUrgentData |
| * At this point, there seems to be no specific requirement to support |
| * this for an SSLSocket. An implementation can be provided if a need |
| * arises in future. |
| */ |
| public final void sendUrgentData(int data) throws SocketException { |
| throw new SocketException("This method is not supported " |
| + "by SSLSockets"); |
| } |
| |
| /** |
| * Enable/disable OOBINLINE (receipt of TCP urgent data) By default, this |
| * option is disabled and TCP urgent data received on a socket is silently |
| * discarded. |
| * @see java.net.Socket#setOOBInline |
| * Setting OOBInline does not have any effect on SSLSocket, |
| * since currently we don't support sending urgent data. |
| */ |
| public final void setOOBInline(boolean on) throws SocketException { |
| throw new SocketException("This method is ineffective, since" |
| + " sending urgent data is not supported by SSLSockets"); |
| } |
| |
| /** |
| * Tests if OOBINLINE is enabled. |
| * @see java.net.Socket#getOOBInline |
| */ |
| public final boolean getOOBInline() throws SocketException { |
| throw new SocketException("This method is ineffective, since" |
| + " sending urgent data is not supported by SSLSockets"); |
| } |
| |
| /** |
| * Returns the socket timeout. |
| * @see java.net.Socket#getSoTimeout |
| */ |
| public final int getSoTimeout() throws SocketException { |
| if (self == this) { |
| return super.getSoTimeout(); |
| } else { |
| return self.getSoTimeout(); |
| } |
| } |
| |
| public final void setSendBufferSize(int size) throws SocketException { |
| if (self == this) { |
| super.setSendBufferSize(size); |
| } else { |
| self.setSendBufferSize(size); |
| } |
| } |
| |
| public final int getSendBufferSize() throws SocketException { |
| if (self == this) { |
| return super.getSendBufferSize(); |
| } else { |
| return self.getSendBufferSize(); |
| } |
| } |
| |
| public final void setReceiveBufferSize(int size) throws SocketException { |
| if (self == this) { |
| super.setReceiveBufferSize(size); |
| } else { |
| self.setReceiveBufferSize(size); |
| } |
| } |
| |
| public final int getReceiveBufferSize() throws SocketException { |
| if (self == this) { |
| return super.getReceiveBufferSize(); |
| } else { |
| return self.getReceiveBufferSize(); |
| } |
| } |
| |
| /** |
| * Enable/disable SO_KEEPALIVE. |
| * @see java.net.Socket#setKeepAlive |
| */ |
| public final void setKeepAlive(boolean on) throws SocketException { |
| if (self == this) { |
| super.setKeepAlive(on); |
| } else { |
| self.setKeepAlive(on); |
| } |
| } |
| |
| /** |
| * Tests if SO_KEEPALIVE is enabled. |
| * @see java.net.Socket#getKeepAlive |
| */ |
| public final boolean getKeepAlive() throws SocketException { |
| if (self == this) { |
| return super.getKeepAlive(); |
| } else { |
| return self.getKeepAlive(); |
| } |
| } |
| |
| /** |
| * Sets traffic class or type-of-service octet in the IP header for |
| * packets sent from this Socket. |
| * @see java.net.Socket#setTrafficClass |
| */ |
| public final void setTrafficClass(int tc) throws SocketException { |
| if (self == this) { |
| super.setTrafficClass(tc); |
| } else { |
| self.setTrafficClass(tc); |
| } |
| } |
| |
| /** |
| * Gets traffic class or type-of-service in the IP header for packets |
| * sent from this Socket. |
| * @see java.net.Socket#getTrafficClass |
| */ |
| public final int getTrafficClass() throws SocketException { |
| if (self == this) { |
| return super.getTrafficClass(); |
| } else { |
| return self.getTrafficClass(); |
| } |
| } |
| |
| /** |
| * Enable/disable SO_REUSEADDR. |
| * @see java.net.Socket#setReuseAddress |
| */ |
| public final void setReuseAddress(boolean on) throws SocketException { |
| if (self == this) { |
| super.setReuseAddress(on); |
| } else { |
| self.setReuseAddress(on); |
| } |
| } |
| |
| /** |
| * Tests if SO_REUSEADDR is enabled. |
| * @see java.net.Socket#getReuseAddress |
| */ |
| public final boolean getReuseAddress() throws SocketException { |
| if (self == this) { |
| return super.getReuseAddress(); |
| } else { |
| return self.getReuseAddress(); |
| } |
| } |
| |
| /** |
| * Sets performance preferences for this socket. |
| * |
| * @see java.net.Socket#setPerformancePreferences(int, int, int) |
| */ |
| public void setPerformancePreferences(int connectionTime, |
| int latency, int bandwidth) { |
| if (self == this) { |
| super.setPerformancePreferences( |
| connectionTime, latency, bandwidth); |
| } else { |
| self.setPerformancePreferences( |
| connectionTime, latency, bandwidth); |
| } |
| } |
| |
| } |