Exemplo n.º 1
0
/** @author Stuart Douglas */
class UndertowSslConnection extends SslConnection {

  private static final Set<Option<?>> SUPPORTED_OPTIONS =
      Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create();

  private final StreamConnection delegate;
  private final SslConduit sslConduit;
  private final ChannelListener.SimpleSetter<SslConnection> handshakeSetter =
      new ChannelListener.SimpleSetter<>();
  private final SSLEngine engine;

  /**
   * Construct a new instance.
   *
   * @param delegate the underlying connection
   */
  UndertowSslConnection(StreamConnection delegate, SSLEngine engine, ByteBufferPool bufferPool) {
    super(delegate.getIoThread());
    this.delegate = delegate;
    this.engine = engine;
    sslConduit = new SslConduit(this, delegate, engine, bufferPool, new HandshakeCallback());
    setSourceConduit(sslConduit);
    setSinkConduit(sslConduit);
  }

  @Override
  public void startHandshake() throws IOException {
    sslConduit.startHandshake();
  }

  @Override
  public SSLSession getSslSession() {
    return sslConduit.getSslSession();
  }

  @Override
  public ChannelListener.Setter<? extends SslConnection> getHandshakeSetter() {
    return handshakeSetter;
  }

  @Override
  protected void notifyWriteClosed() {
    sslConduit.notifyWriteClosed();
  }

  @Override
  protected void notifyReadClosed() {
    sslConduit.notifyReadClosed();
  }

  @Override
  public SocketAddress getPeerAddress() {
    return delegate.getPeerAddress();
  }

  @Override
  public SocketAddress getLocalAddress() {
    return delegate.getLocalAddress();
  }

  public SSLEngine getSSLEngine() {
    return sslConduit.getSSLEngine();
  }

  SslConduit getSslConduit() {
    return sslConduit;
  }

  /** {@inheritDoc} */
  @Override
  public <T> T setOption(final Option<T> option, final T value)
      throws IllegalArgumentException, IOException {
    if (option == Options.SSL_CLIENT_AUTH_MODE) {
      try {
        return option.cast(
            engine.getNeedClientAuth()
                ? SslClientAuthMode.REQUIRED
                : engine.getWantClientAuth()
                    ? SslClientAuthMode.REQUESTED
                    : SslClientAuthMode.NOT_REQUESTED);
      } finally {
        engine.setNeedClientAuth(value == SslClientAuthMode.REQUIRED);
        engine.setWantClientAuth(value == SslClientAuthMode.REQUESTED);
      }
    } else if (option == Options.SECURE) {
      throw new IllegalArgumentException();
    } else {
      return delegate.setOption(option, value);
    }
  }

  /** {@inheritDoc} */
  @Override
  public <T> T getOption(final Option<T> option) throws IOException {
    if (option == Options.SSL_CLIENT_AUTH_MODE) {
      return option.cast(
          engine.getNeedClientAuth()
              ? SslClientAuthMode.REQUIRED
              : engine.getWantClientAuth()
                  ? SslClientAuthMode.REQUESTED
                  : SslClientAuthMode.NOT_REQUESTED);
    } else {
      return option == Options.SECURE ? (T) Boolean.TRUE : delegate.getOption(option);
    }
  }

  /** {@inheritDoc} */
  @Override
  public boolean supportsOption(final Option<?> option) {
    return SUPPORTED_OPTIONS.contains(option) || delegate.supportsOption(option);
  }

  @Override
  protected boolean readClosed() {
    return super.readClosed();
  }

  @Override
  protected boolean writeClosed() {
    return super.writeClosed();
  }

  protected void closeAction() {
    sslConduit.close();
  }

  private final class HandshakeCallback implements Runnable {

    @Override
    public void run() {
      final ChannelListener<? super SslConnection> listener = handshakeSetter.get();
      if (listener == null) {
        return;
      }
      ChannelListeners.<SslConnection>invokeChannelListener(UndertowSslConnection.this, listener);
    }
  }
}