mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			741 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			741 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Java
		
	
	
	
/* SSLSocketImpl.java -- implementation of an SSL client socket.
 | 
						|
   Copyright (C) 2006  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is a part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2 of the License, or (at
 | 
						|
your option) any later version.
 | 
						|
 | 
						|
GNU Classpath 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 for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; if not, write to the Free Software
 | 
						|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 | 
						|
USA
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.javax.net.ssl.provider;
 | 
						|
 | 
						|
import gnu.classpath.debug.Component;
 | 
						|
import gnu.classpath.debug.SystemLogger;
 | 
						|
 | 
						|
import java.io.DataInputStream;
 | 
						|
import java.io.EOFException;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.OutputStream;
 | 
						|
import java.net.InetAddress;
 | 
						|
import java.net.Socket;
 | 
						|
import java.net.SocketAddress;
 | 
						|
import java.net.SocketException;
 | 
						|
import java.nio.ByteBuffer;
 | 
						|
import java.nio.channels.SocketChannel;
 | 
						|
import java.util.HashSet;
 | 
						|
import java.util.Set;
 | 
						|
 | 
						|
import javax.net.ssl.HandshakeCompletedEvent;
 | 
						|
import javax.net.ssl.HandshakeCompletedListener;
 | 
						|
import javax.net.ssl.SSLEngineResult;
 | 
						|
import javax.net.ssl.SSLException;
 | 
						|
import javax.net.ssl.SSLSession;
 | 
						|
import javax.net.ssl.SSLSocket;
 | 
						|
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 | 
						|
import javax.net.ssl.SSLEngineResult.Status;
 | 
						|
 | 
						|
/**
 | 
						|
 * @author Casey Marshall (csm@gnu.org)
 | 
						|
 */
 | 
						|
public class SSLSocketImpl extends SSLSocket
 | 
						|
{
 | 
						|
  private class SocketOutputStream extends OutputStream
 | 
						|
  {
 | 
						|
    private final ByteBuffer buffer;
 | 
						|
    private final OutputStream out;
 | 
						|
 | 
						|
    SocketOutputStream() throws IOException
 | 
						|
    {
 | 
						|
      buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
      if (underlyingSocket != null)
 | 
						|
        out = underlyingSocket.getOutputStream();
 | 
						|
      else
 | 
						|
        out = SSLSocketImpl.super.getOutputStream();
 | 
						|
    }
 | 
						|
 | 
						|
    @Override public void write(byte[] buf, int off, int len) throws IOException
 | 
						|
    {
 | 
						|
      if (!initialHandshakeDone
 | 
						|
          || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
 | 
						|
        {
 | 
						|
          doHandshake();
 | 
						|
          if (handshakeException != null)
 | 
						|
            throw handshakeException;
 | 
						|
        }
 | 
						|
 | 
						|
      int k = 0;
 | 
						|
      while (k < len)
 | 
						|
        {
 | 
						|
          synchronized (engine)
 | 
						|
            {
 | 
						|
              int l = Math.min(len-k, getSession().getApplicationBufferSize());
 | 
						|
              ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
 | 
						|
              SSLEngineResult result = engine.wrap(in, buffer);
 | 
						|
              if (result.getStatus() == Status.CLOSED)
 | 
						|
                return;
 | 
						|
              if (result.getStatus() != Status.OK)
 | 
						|
                throw new SSLException("unexpected SSL state " + result.getStatus());
 | 
						|
              buffer.flip();
 | 
						|
              out.write(buffer.array(), 0, buffer.limit());
 | 
						|
              k += result.bytesConsumed();
 | 
						|
              buffer.clear();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    @Override public void write(int b) throws IOException
 | 
						|
    {
 | 
						|
      write(new byte[] { (byte) b });
 | 
						|
    }
 | 
						|
 | 
						|
    @Override public void close() throws IOException
 | 
						|
    {
 | 
						|
      SSLSocketImpl.this.close();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private class SocketInputStream extends InputStream
 | 
						|
  {
 | 
						|
    private final ByteBuffer inBuffer;
 | 
						|
    private final ByteBuffer appBuffer;
 | 
						|
    private final DataInputStream in;
 | 
						|
 | 
						|
    SocketInputStream() throws IOException
 | 
						|
    {
 | 
						|
      inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
      inBuffer.limit(0);
 | 
						|
      appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
 | 
						|
      appBuffer.flip();
 | 
						|
      if (underlyingSocket != null)
 | 
						|
        in = new DataInputStream(underlyingSocket.getInputStream());
 | 
						|
      else
 | 
						|
        in = new DataInputStream(SSLSocketImpl.super.getInputStream());
 | 
						|
    }
 | 
						|
 | 
						|
    @Override public int read(byte[] buf, int off, int len) throws IOException
 | 
						|
    {
 | 
						|
      if (!initialHandshakeDone ||
 | 
						|
          engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
 | 
						|
        {
 | 
						|
          doHandshake();
 | 
						|
          if (handshakeException != null)
 | 
						|
            throw handshakeException;
 | 
						|
        }
 | 
						|
 | 
						|
      if (!appBuffer.hasRemaining())
 | 
						|
        {
 | 
						|
          int x = in.read();
 | 
						|
          if (x == -1)
 | 
						|
            return -1;
 | 
						|
          inBuffer.clear();
 | 
						|
          inBuffer.put((byte) x);
 | 
						|
          inBuffer.putInt(in.readInt());
 | 
						|
          int reclen = inBuffer.getShort(3) & 0xFFFF;
 | 
						|
          in.readFully(inBuffer.array(), 5, reclen);
 | 
						|
          inBuffer.position(0).limit(reclen + 5);
 | 
						|
          synchronized (engine)
 | 
						|
            {
 | 
						|
              appBuffer.clear();
 | 
						|
              SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
 | 
						|
              Status status = result.getStatus();
 | 
						|
              if (status == Status.CLOSED && result.bytesProduced() == 0)
 | 
						|
                return -1;
 | 
						|
            }
 | 
						|
          inBuffer.compact();
 | 
						|
          appBuffer.flip();
 | 
						|
        }
 | 
						|
      int l = Math.min(len, appBuffer.remaining());
 | 
						|
      appBuffer.get(buf, off, l);
 | 
						|
      return l;
 | 
						|
    }
 | 
						|
 | 
						|
    @Override public int read() throws IOException
 | 
						|
    {
 | 
						|
      byte[] b = new byte[1];
 | 
						|
      if (read(b) == -1)
 | 
						|
        return -1;
 | 
						|
      return b[0] & 0xFF;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private static final SystemLogger logger = SystemLogger.getSystemLogger();
 | 
						|
 | 
						|
  private SSLEngineImpl engine;
 | 
						|
  private Set<HandshakeCompletedListener> listeners;
 | 
						|
  private Socket underlyingSocket;
 | 
						|
  private boolean isHandshaking;
 | 
						|
  private IOException handshakeException;
 | 
						|
  private boolean initialHandshakeDone = false;
 | 
						|
  private final boolean autoClose;
 | 
						|
 | 
						|
  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
 | 
						|
  {
 | 
						|
    this(contextImpl, host, port, new Socket(), true);
 | 
						|
  }
 | 
						|
 | 
						|
  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
 | 
						|
                       Socket underlyingSocket, boolean autoClose)
 | 
						|
  {
 | 
						|
    engine = new SSLEngineImpl(contextImpl, host, port);
 | 
						|
    engine.setUseClientMode(true); // default to client mode
 | 
						|
    listeners = new HashSet<HandshakeCompletedListener>();
 | 
						|
    this.underlyingSocket = underlyingSocket;
 | 
						|
    this.autoClose = autoClose;
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
 | 
						|
   */
 | 
						|
  @Override
 | 
						|
  public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
 | 
						|
  {
 | 
						|
    listeners.add(listener);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
 | 
						|
   */
 | 
						|
  @Override public boolean getEnableSessionCreation()
 | 
						|
  {
 | 
						|
    return engine.getEnableSessionCreation();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
 | 
						|
   */
 | 
						|
  @Override public String[] getEnabledCipherSuites()
 | 
						|
  {
 | 
						|
    return engine.getEnabledCipherSuites();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
 | 
						|
   */
 | 
						|
  @Override public String[] getEnabledProtocols()
 | 
						|
  {
 | 
						|
    return engine.getEnabledProtocols();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
 | 
						|
   */
 | 
						|
  @Override public boolean getNeedClientAuth()
 | 
						|
  {
 | 
						|
    return engine.getNeedClientAuth();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getSession()
 | 
						|
   */
 | 
						|
  @Override public SSLSession getSession()
 | 
						|
  {
 | 
						|
    return engine.getSession();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
 | 
						|
   */
 | 
						|
  @Override public String[] getSupportedCipherSuites()
 | 
						|
  {
 | 
						|
    return engine.getSupportedCipherSuites();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
 | 
						|
   */
 | 
						|
  @Override public String[] getSupportedProtocols()
 | 
						|
  {
 | 
						|
    return engine.getSupportedProtocols();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getUseClientMode()
 | 
						|
   */
 | 
						|
  @Override public boolean getUseClientMode()
 | 
						|
  {
 | 
						|
    return engine.getUseClientMode();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#getWantClientAuth()
 | 
						|
   */
 | 
						|
  @Override public boolean getWantClientAuth()
 | 
						|
  {
 | 
						|
    return engine.getWantClientAuth();
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
 | 
						|
   */
 | 
						|
  @Override
 | 
						|
  public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
 | 
						|
  {
 | 
						|
    listeners.remove(listener);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
 | 
						|
   */
 | 
						|
  @Override public void setEnableSessionCreation(boolean enable)
 | 
						|
  {
 | 
						|
    engine.setEnableSessionCreation(enable);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
 | 
						|
   */
 | 
						|
  @Override public void setEnabledCipherSuites(String[] suites)
 | 
						|
  {
 | 
						|
    engine.setEnabledCipherSuites(suites);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
 | 
						|
   */
 | 
						|
  @Override public void setEnabledProtocols(String[] protocols)
 | 
						|
  {
 | 
						|
    engine.setEnabledProtocols(protocols);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
 | 
						|
   */
 | 
						|
  @Override public void setNeedClientAuth(boolean needAuth)
 | 
						|
  {
 | 
						|
    engine.setNeedClientAuth(needAuth);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
 | 
						|
   */
 | 
						|
  @Override public void setUseClientMode(boolean clientMode)
 | 
						|
  {
 | 
						|
    engine.setUseClientMode(clientMode);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
 | 
						|
   */
 | 
						|
  @Override public void setWantClientAuth(boolean wantAuth)
 | 
						|
  {
 | 
						|
    engine.setWantClientAuth(wantAuth);
 | 
						|
  }
 | 
						|
 | 
						|
  /* (non-Javadoc)
 | 
						|
   * @see javax.net.ssl.SSLSocket#startHandshake()
 | 
						|
   */
 | 
						|
  @Override public void startHandshake() throws IOException
 | 
						|
  {
 | 
						|
    if (isHandshaking)
 | 
						|
      return;
 | 
						|
 | 
						|
    if (handshakeException != null)
 | 
						|
      throw handshakeException;
 | 
						|
 | 
						|
    Thread t = new Thread(new Runnable()
 | 
						|
    {
 | 
						|
      public void run()
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            doHandshake();
 | 
						|
          }
 | 
						|
        catch (IOException ioe)
 | 
						|
          {
 | 
						|
            handshakeException = ioe;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    }, "HandshakeThread@" + System.identityHashCode(this));
 | 
						|
    t.start();
 | 
						|
  }
 | 
						|
 | 
						|
  void doHandshake() throws IOException
 | 
						|
  {
 | 
						|
    synchronized (engine)
 | 
						|
      {
 | 
						|
        if (isHandshaking)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                engine.wait();
 | 
						|
              }
 | 
						|
            catch (InterruptedException ie)
 | 
						|
              {
 | 
						|
              }
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        isHandshaking = true;
 | 
						|
      }
 | 
						|
 | 
						|
    if (initialHandshakeDone)
 | 
						|
      throw new SSLException("rehandshaking not yet implemented");
 | 
						|
 | 
						|
    long now = -System.currentTimeMillis();
 | 
						|
    engine.beginHandshake();
 | 
						|
 | 
						|
    HandshakeStatus status = engine.getHandshakeStatus();
 | 
						|
    assert(status != HandshakeStatus.NOT_HANDSHAKING);
 | 
						|
 | 
						|
    ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
    inBuffer.position(inBuffer.limit());
 | 
						|
    ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
    ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
 | 
						|
    SSLEngineResult result = null;
 | 
						|
 | 
						|
    DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream());
 | 
						|
    OutputStream sockOut = underlyingSocket.getOutputStream();
 | 
						|
 | 
						|
    try
 | 
						|
      {
 | 
						|
        while (status != HandshakeStatus.NOT_HANDSHAKING
 | 
						|
               && status != HandshakeStatus.FINISHED)
 | 
						|
          {
 | 
						|
            logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
 | 
						|
                        status);
 | 
						|
 | 
						|
            if (inBuffer.capacity() != getSession().getPacketBufferSize())
 | 
						|
              {
 | 
						|
                ByteBuffer b
 | 
						|
                  = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
                if (inBuffer.hasRemaining())
 | 
						|
                  b.put(inBuffer).flip();
 | 
						|
                inBuffer = b;
 | 
						|
              }
 | 
						|
            if (outBuffer.capacity() != getSession().getPacketBufferSize())
 | 
						|
              outBuffer
 | 
						|
              = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
 | 
						|
 | 
						|
            switch (status)
 | 
						|
              {
 | 
						|
                case NEED_UNWRAP:
 | 
						|
                  // Read in a single SSL record.
 | 
						|
                  inBuffer.clear();
 | 
						|
                  int i = sockIn.read();
 | 
						|
                  if (i == -1)
 | 
						|
                    throw new EOFException();
 | 
						|
                  if ((i & 0x80) == 0x80) // SSLv2 client hello.
 | 
						|
                    {
 | 
						|
                      inBuffer.put((byte) i);
 | 
						|
                      int v2len = (i & 0x7f) << 8;
 | 
						|
                      i = sockIn.read();
 | 
						|
                      v2len = v2len | (i & 0xff);
 | 
						|
                      inBuffer.put((byte) i);
 | 
						|
                      sockIn.readFully(inBuffer.array(), 2, v2len);
 | 
						|
                      inBuffer.position(0).limit(v2len + 2);
 | 
						|
                    }
 | 
						|
                  else
 | 
						|
                    {
 | 
						|
                      inBuffer.put((byte) i);
 | 
						|
                      inBuffer.putInt(sockIn.readInt());
 | 
						|
                      int reclen = inBuffer.getShort(3) & 0xFFFF;
 | 
						|
                      sockIn.readFully(inBuffer.array(), 5, reclen);
 | 
						|
                      inBuffer.position(0).limit(reclen + 5);
 | 
						|
                    }
 | 
						|
                  result = engine.unwrap(inBuffer, emptyBuffer);
 | 
						|
                  status = result.getHandshakeStatus();
 | 
						|
                  if (result.getStatus() != Status.OK)
 | 
						|
                    throw new SSLException("unexpected SSL status "
 | 
						|
                                           + result.getStatus());
 | 
						|
                  break;
 | 
						|
 | 
						|
                case NEED_WRAP:
 | 
						|
                {
 | 
						|
                  outBuffer.clear();
 | 
						|
                  result = engine.wrap(emptyBuffer, outBuffer);
 | 
						|
                  status = result.getHandshakeStatus();
 | 
						|
                  if (result.getStatus() != Status.OK)
 | 
						|
                    throw new SSLException("unexpected SSL status "
 | 
						|
                                           + result.getStatus());
 | 
						|
                  outBuffer.flip();
 | 
						|
                  sockOut.write(outBuffer.array(), outBuffer.position(),
 | 
						|
                                outBuffer.limit());
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case NEED_TASK:
 | 
						|
                {
 | 
						|
                  Runnable task;
 | 
						|
                  while ((task = engine.getDelegatedTask()) != null)
 | 
						|
                    task.run();
 | 
						|
                  status = engine.getHandshakeStatus();
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case FINISHED:
 | 
						|
                  break;
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        initialHandshakeDone = true;
 | 
						|
 | 
						|
        HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
 | 
						|
        for (HandshakeCompletedListener l : listeners)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                l.handshakeCompleted(hce);
 | 
						|
              }
 | 
						|
            catch (ThreadDeath td)
 | 
						|
              {
 | 
						|
                throw td;
 | 
						|
              }
 | 
						|
            catch (Throwable x)
 | 
						|
              {
 | 
						|
                logger.log(Component.WARNING,
 | 
						|
                           "HandshakeCompletedListener threw exception", x);
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        now += System.currentTimeMillis();
 | 
						|
        if (Debug.DEBUG)
 | 
						|
          logger.logv(Component.SSL_HANDSHAKE,
 | 
						|
                      "handshake completed in {0}ms in thread {1}", now,
 | 
						|
                      Thread.currentThread().getName());
 | 
						|
      }
 | 
						|
    catch (SSLException ssle)
 | 
						|
      {
 | 
						|
        handshakeException = ssle;
 | 
						|
        throw ssle;
 | 
						|
      }
 | 
						|
    finally
 | 
						|
      {
 | 
						|
        synchronized (engine)
 | 
						|
          {
 | 
						|
            isHandshaking = false;
 | 
						|
            engine.notifyAll();
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // Methods overriding Socket.
 | 
						|
 | 
						|
  @Override public void bind(SocketAddress bindpoint) throws IOException
 | 
						|
  {
 | 
						|
    underlyingSocket.bind(bindpoint);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void connect(SocketAddress endpoint) throws IOException
 | 
						|
  {
 | 
						|
    underlyingSocket.connect(endpoint);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void connect(SocketAddress endpoint, int timeout)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    underlyingSocket.connect(endpoint, timeout);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public InetAddress getInetAddress()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getInetAddress();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public InetAddress getLocalAddress()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getLocalAddress();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getPort()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getPort();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getLocalPort()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getLocalPort();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public SocketAddress getRemoteSocketAddress()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getRemoteSocketAddress();
 | 
						|
  }
 | 
						|
 | 
						|
  public SocketAddress getLocalSocketAddress()
 | 
						|
  {
 | 
						|
    return underlyingSocket.getLocalSocketAddress();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public SocketChannel getChannel()
 | 
						|
  {
 | 
						|
    throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public InputStream getInputStream() throws IOException
 | 
						|
  {
 | 
						|
    return new SocketInputStream();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public OutputStream getOutputStream() throws IOException
 | 
						|
  {
 | 
						|
    return new SocketOutputStream();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setTcpNoDelay(boolean on) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setTcpNoDelay(on);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean getTcpNoDelay() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getTcpNoDelay();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setSoLinger(boolean on, int linger) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setSoLinger(on, linger);
 | 
						|
  }
 | 
						|
 | 
						|
  public int getSoLinger() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getSoLinger();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void sendUrgentData(int x) throws IOException
 | 
						|
  {
 | 
						|
    throw new UnsupportedOperationException("not supported");
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setOOBInline(boolean on) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setOOBInline(on);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean getOOBInline() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getOOBInline();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setSoTimeout(int timeout) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setSoTimeout(timeout);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getSoTimeout() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getSoTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setSendBufferSize(int size) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setSendBufferSize(size);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getSendBufferSize() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getSendBufferSize();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setReceiveBufferSize(int size) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setReceiveBufferSize(size);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getReceiveBufferSize() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getReceiveBufferSize();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setKeepAlive(boolean on) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setKeepAlive(on);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean getKeepAlive() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getKeepAlive();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setTrafficClass(int tc) throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setTrafficClass(tc);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public int getTrafficClass() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getTrafficClass();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void setReuseAddress(boolean reuseAddress)
 | 
						|
    throws SocketException
 | 
						|
  {
 | 
						|
    underlyingSocket.setReuseAddress(reuseAddress);
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean getReuseAddress() throws SocketException
 | 
						|
  {
 | 
						|
    return underlyingSocket.getReuseAddress();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void close() throws IOException
 | 
						|
  {
 | 
						|
    // XXX closure alerts.
 | 
						|
    if (autoClose)
 | 
						|
      underlyingSocket.close();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void shutdownInput() throws IOException
 | 
						|
  {
 | 
						|
    underlyingSocket.shutdownInput();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public void shutdownOutput() throws IOException
 | 
						|
  {
 | 
						|
    underlyingSocket.shutdownOutput();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean isConnected()
 | 
						|
  {
 | 
						|
    return underlyingSocket.isConnected();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean isBound()
 | 
						|
  {
 | 
						|
    return underlyingSocket.isBound();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean isClosed()
 | 
						|
  {
 | 
						|
    return underlyingSocket.isClosed();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean isInputShutdown()
 | 
						|
  {
 | 
						|
    return underlyingSocket.isInputShutdown();
 | 
						|
  }
 | 
						|
 | 
						|
  @Override public boolean isOutputShutdown()
 | 
						|
  {
 | 
						|
    return underlyingSocket.isOutputShutdown();
 | 
						|
  }
 | 
						|
}
 |