SecureServerSocketChannel.java

/*
 * Copyright Radoslav Husar and contributors
 * SPDX-License-Identifier: Apache-2.0
 */
package io.github.rhusar.securenio.channels;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

/**
 * A {@link ServerSocketChannel} decorator that wraps a raw server socket channel, producing
 * {@link SecureSocketChannel} instances for each accepted connection. The TLS engine for each
 * accepted channel is configured in server mode using the provided {@link SSLContext}.
 * <p>
 * Non-accept operations are delegated transparently to the underlying raw server channel.
 *
 * @author Radoslav Husar
 */
public class SecureServerSocketChannel extends ServerSocketChannel {

    private final ServerSocketChannel delegate;
    private final SSLContext sslContext;
    private final ExecutorService taskExecutor;

    public SecureServerSocketChannel(ServerSocketChannel delegate, SSLContext sslContext, ExecutorService taskExecutor) {
        super(delegate.provider());

        this.delegate = delegate;
        this.sslContext = sslContext;
        this.taskExecutor = taskExecutor;
    }

    /**
     * Returns the underlying raw (unencrypted) server channel.
     */
    public ServerSocketChannel delegate() {
        return delegate;
    }

    @Override
    public SocketChannel accept() throws IOException {
        SocketChannel rawChannel = delegate.accept();
        if (rawChannel == null) {
            return null;
        }

        SSLEngine engine = sslContext.createSSLEngine();
        engine.setUseClientMode(false);

        return new SecureSocketChannel(rawChannel, engine, taskExecutor);
    }

    @Override
    protected void implCloseSelectableChannel() throws IOException {
        delegate.close();
    }

    @Override
    protected void implConfigureBlocking(boolean block) throws IOException {
        delegate.configureBlocking(block);
    }

    @Override
    public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
        delegate.bind(local, backlog);
        return this;
    }

    @Override
    public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) throws IOException {
        delegate.setOption(name, value);
        return this;
    }

    @Override
    public <T> T getOption(SocketOption<T> name) throws IOException {
        return delegate.getOption(name);
    }

    @Override
    public Set<SocketOption<?>> supportedOptions() {
        return delegate.supportedOptions();
    }

    @Override
    public ServerSocket socket() {
        return delegate.socket();
    }

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

}