All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aoju.bus.socket.origin.SSLAioSession Maven / Gradle / Ivy

There is a newer version: 8.0.0
Show newest version
/*
 * The MIT License
 *
 * Copyright (c) 2017 aoju.org All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.aoju.bus.socket.origin;

import org.aoju.bus.core.io.segment.BufferPage;
import org.aoju.bus.core.io.segment.VirtualBuffer;
import org.aoju.bus.logger.Logger;
import org.aoju.bus.socket.origin.plugins.ssl.Callback;
import org.aoju.bus.socket.origin.plugins.ssl.Handshake;
import org.aoju.bus.socket.origin.plugins.ssl.SSLService;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;

/**
 * @author Kimi Liu
 * @version 5.0.8
 * @since JDK 1.8+
 */
class SSLAioSession extends TcpAioSession {

    private ByteBuffer netWriteBuffer;

    private ByteBuffer netReadBuffer;
    private SSLEngine sslEngine = null;

    /**
     * 完成握手置null
     */
    private Handshake handshakeModel;
    /**
     * 完成握手置null
     */
    private SSLService sslService;

    /**
     * @param channel
     * @param config
     * @param aioReadCompletionHandler
     * @param aioWriteCompletionHandler
     * @param sslService                是否服务端Session
     */
    SSLAioSession(AsynchronousSocketChannel channel, ServerConfig config, TcpReadHandler aioReadCompletionHandler, TcpWriteHandler aioWriteCompletionHandler, SSLService sslService, BufferPage bufferPage) {
        super(channel, config, aioReadCompletionHandler, aioWriteCompletionHandler, bufferPage);
        this.handshakeModel = sslService.createSSLEngine(channel);
        this.sslService = sslService;
    }

    @Override
    void writeToChannel() {
        checkInitialized();
        if (netWriteBuffer != null && netWriteBuffer.hasRemaining()) {
            writeToChannel0(netWriteBuffer);
            return;
        }
        super.writeToChannel();
    }


    @Override
    void initSession() {
        this.sslEngine = handshakeModel.getSslEngine();
        this.netWriteBuffer = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
        this.netWriteBuffer.flip();
        this.netReadBuffer = ByteBuffer.allocate(readBuffer.buffer().capacity());
        this.handshakeModel.setHandshakeCallback(new Callback() {
            @Override
            public void callback() {
                synchronized (SSLAioSession.this) {
                    handshakeModel = null;//释放内存
                    SSLAioSession.this.notifyAll();
                }
                sslService = null;//释放内存
                continueRead();
            }
        });
        sslService.doHandshake(handshakeModel);
    }

    /**
     * 校验是否已完成初始化,如果还处于Handshake阶段则阻塞当前线程
     */
    private void checkInitialized() {
        if (handshakeModel == null) {
            return;
        }
        synchronized (this) {
            if (handshakeModel == null) {
                return;
            }
            try {
                this.wait();
            } catch (InterruptedException e) {
                Logger.debug(e.getMessage(), e);
            }
        }
    }

    @Override
    void readFromChannel(boolean eof) {
        checkInitialized();
        doUnWrap();
        super.readFromChannel(eof);
    }

    @Override
    protected void continueRead() {
        readFromChannel0(netReadBuffer);
    }

    @Override
    protected void continueWrite(VirtualBuffer writeBuffer) {
        doWrap(writeBuffer);
        writeToChannel0(netWriteBuffer);
    }

    private void doWrap(VirtualBuffer writeBuffer) {
        try {
            netWriteBuffer.compact();
            SSLEngineResult result = sslEngine.wrap(writeBuffer.buffer(), netWriteBuffer);
            while (result.getStatus() != SSLEngineResult.Status.OK) {
                switch (result.getStatus()) {
                    case BUFFER_OVERFLOW:
                        Logger.info("doWrap BUFFER_OVERFLOW");
                        break;
                    case BUFFER_UNDERFLOW:
                        Logger.info("doWrap BUFFER_UNDERFLOW");
                        break;
                    default:
                        Logger.error("doWrap Result:" + result.getStatus());
                }
                result = sslEngine.wrap(writeBuffer.buffer(), netWriteBuffer);
            }
            netWriteBuffer.flip();
        } catch (SSLException e) {
            throw new RuntimeException(e);
        }
    }

    private void doUnWrap() {
        try {
            netReadBuffer.flip();
            ByteBuffer readBuffer = super.readBuffer.buffer();
            SSLEngineResult result = sslEngine.unwrap(netReadBuffer, readBuffer);
            boolean closed = false;
            while (!closed && result.getStatus() != SSLEngineResult.Status.OK) {
                switch (result.getStatus()) {
                    case BUFFER_OVERFLOW:
                        // Could attempt to drain the dst buffer of any already obtained
                        // data, but we'll just increase it to the size needed.
                        int appSize = readBuffer.capacity() * 2 < sslEngine.getSession().getApplicationBufferSize() ? readBuffer.capacity() * 2 : sslEngine.getSession().getApplicationBufferSize();
                        Logger.info("doUnWrap BUFFER_OVERFLOW:" + appSize);
                        ByteBuffer b = ByteBuffer.allocate(appSize + readBuffer.position());
                        readBuffer.flip();
                        b.put(readBuffer);
                        readBuffer = b;
                        // retry the operation.
                        break;
                    case BUFFER_UNDERFLOW:

                        if (netReadBuffer.limit() == netReadBuffer.capacity()) {
                            int netSize = netReadBuffer.capacity() * 2 < sslEngine.getSession().getPacketBufferSize() ? netReadBuffer.capacity() * 2 : sslEngine.getSession().getPacketBufferSize();
                            Logger.debug("BUFFER_UNDERFLOW:" + netSize);
                            ByteBuffer b1 = ByteBuffer.allocate(netSize);
                            b1.put(netReadBuffer);
                            netReadBuffer = b1;
                        } else {
                            if (netReadBuffer.position() > 0) {
                                netReadBuffer.compact();
                            } else {
                                netReadBuffer.position(netReadBuffer.limit());
                                netReadBuffer.limit(netReadBuffer.capacity());
                            }
                            Logger.debug("BUFFER_UNDERFLOW,continue read:" + netReadBuffer);
                        }

                        return;
                    case CLOSED:
                        Logger.debug("doUnWrap Result:" + result.getStatus());
                        closed = true;
                        break;
                    default:
                        Logger.error("doUnWrap Result:" + result.getStatus());
                        // other cases: CLOSED, OK.
                }
                result = sslEngine.unwrap(netReadBuffer, readBuffer);
            }
            netReadBuffer.compact();
        } catch (SSLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void close(boolean immediate) {
        super.close(immediate);
        if (status == SESSION_STATUS_CLOSED) {
            sslEngine.closeOutbound();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy