package org.xnio.ssl;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.Set;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import org.xnio.ChannelListener;
import org.xnio.ChannelListeners;
import org.xnio.Option;
import org.xnio.Options;
import org.xnio.Pool;
import org.xnio.SslClientAuthMode;
import org.xnio.StreamConnection;
public final class JsseSslConnection extends SslConnection {
private final StreamConnection streamConnection;
private final JsseStreamConduit conduit;
private final ChannelListener.SimpleSetter<SslConnection> handshakeSetter = new ChannelListener.SimpleSetter<>();
public JsseSslConnection(final StreamConnection streamConnection, final SSLEngine engine) {
this(streamConnection, engine, JsseXnioSsl.bufferPool, JsseXnioSsl.bufferPool);
}
JsseSslConnection(final StreamConnection streamConnection, final SSLEngine engine, final Pool<ByteBuffer> socketBufferPool, final Pool<ByteBuffer> applicationBufferPool) {
super(streamConnection.getIoThread());
this.streamConnection = streamConnection;
conduit = new JsseStreamConduit(this, engine, streamConnection.getSourceChannel().getConduit(), streamConnection.getSinkChannel().getConduit(), socketBufferPool, applicationBufferPool);
setSourceConduit(conduit);
setSinkConduit(conduit);
}
public void startHandshake() throws IOException {
conduit.beginHandshake();
}
public SSLSession getSslSession() {
return conduit.getSslSession();
}
protected void closeAction() throws IOException {
try {
if (!conduit.isWriteShutdown()) {
conduit.terminateWrites();
}
if (!conduit.isReadShutdown()) {
conduit.terminateReads();
}
conduit.flush();
conduit.markTerminated();
streamConnection.close();
} catch (Throwable t) {
try {
if (!conduit.isReadShutdown()) {
conduit.terminateReads();
}
} catch (Throwable ignored) {}
try {
conduit.markTerminated();
streamConnection.close();
} catch (Throwable ignored) {}
throw t;
}
}
protected void notifyWriteClosed() {}
protected void notifyReadClosed() {}
public SocketAddress getPeerAddress() {
return streamConnection.getPeerAddress();
}
public SocketAddress getLocalAddress() {
return streamConnection.getLocalAddress();
}
public ChannelListener.Setter<? extends SslConnection> getHandshakeSetter() {
return handshakeSetter;
}
void invokeHandshakeListener() {
ChannelListeners.invokeChannelListener(this, handshakeSetter.get());
}
@Override
public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
if (option == Options.SSL_CLIENT_AUTH_MODE) {
final SSLEngine engine = conduit.getEngine();
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 streamConnection.setOption(option, value);
}
}
@Override
public <T> T getOption(final Option<T> option) throws IOException {
if (option == Options.SSL_CLIENT_AUTH_MODE) {
final SSLEngine engine = conduit.getEngine();
return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
} else {
return option == Options.SECURE ? option.cast(Boolean.valueOf(conduit.isTls())) : streamConnection.getOption(option);
}
}
private static final Set<Option<?>> SUPPORTED_OPTIONS = Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create();
@Override
public boolean supportsOption(final Option<?> option) {
return SUPPORTED_OPTIONS.contains(option) || streamConnection.supportsOption(option);
}
@Override
public boolean isOpen() {
return streamConnection.isOpen();
}
@Override
public boolean isWriteShutdown() {
return streamConnection.isWriteShutdown();
}
@Override
public boolean isReadShutdown() {
return streamConnection.isReadShutdown();
}
public SSLEngine getEngine() {
return conduit.getEngine();
}
}