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

com.generallycloud.baseio.protocol.SslReadFutureImpl Maven / Gradle / Ivy

/*
 * Copyright 2015-2017 GenerallyCloud.com
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package com.generallycloud.baseio.protocol;

import java.io.IOException;

import com.generallycloud.baseio.buffer.ByteBuf;
import com.generallycloud.baseio.common.ReleaseUtil;
import com.generallycloud.baseio.component.Session;
import com.generallycloud.baseio.component.SocketChannel;
import com.generallycloud.baseio.component.SocketSession;
import com.generallycloud.baseio.component.ssl.SslHandler;

public class SslReadFutureImpl extends AbstractChannelReadFuture implements SslReadFuture {

	private boolean	body_complete;

	private ByteBuf	buf;

	private boolean	header_complete;

	private int		length;

	private int		limit;
	
	private SocketChannel channel;

	public SslReadFutureImpl(SocketChannel channel, ByteBuf buf, int limit) {
		super(channel.getContext());
		this.buf = buf;
		this.limit = limit;
		this.channel = channel;
	}

	private void doBodyComplete(ByteBuf buf) throws IOException {

		body_complete = true;

		buf.flip();

		SslHandler handler = channel.getSslHandler();

		try {

			this.buf = handler.unwrap(channel, buf);

		} finally {
			ReleaseUtil.release(buf);
		}
	}

	private void doHeaderComplete(Session session, ByteBuf buf) throws IOException {

		header_complete = true;

		int length = getEncryptedPacketLength(buf);

		buf.reallocate(length, limit, true);

		this.length = length;
	}

	int getEncryptedPacketLength(ByteBuf buffer) {
		int packetLength = 0;
		int offset = 0;
		// FIXME offset

		// SSLv3 or TLS - Check ContentType
		boolean tls;
		switch (buffer.getUnsignedByte(offset)) {
		case SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
		case SSL_CONTENT_TYPE_ALERT:
		case SSL_CONTENT_TYPE_HANDSHAKE:
		case SSL_CONTENT_TYPE_APPLICATION_DATA:
			tls = true;
			break;
		default:
			// SSLv2 or bad data
			tls = false;
		}

		if (tls) {
			// SSLv3 or TLS - Check ProtocolVersion
			int majorVersion = buffer.getUnsignedByte(offset + 1);
			if (majorVersion == 3) {
				// SSLv3 or TLS
				packetLength = buffer.getUnsignedShort(offset + 3) + SSL_RECORD_HEADER_LENGTH;
				if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
					// Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
					tls = false;
				}
			} else {
				// Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
				tls = false;
			}
		}

		if (!tls) {
			// SSLv2 or bad data - Check the version
			int headerLength = (buffer.getUnsignedByte(offset) & 0x80) != 0 ? 2 : 3;
			int majorVersion = buffer.getUnsignedByte(offset + headerLength + 1);
			if (majorVersion == 2 || majorVersion == 3) {
				// SSLv2
				if (headerLength == 2) {
					packetLength = (buffer.getShort(offset) & 0x7FFF) + 2;
				} else {
					packetLength = (buffer.getShort(offset) & 0x3FFF) + 3;
				}
				if (packetLength <= headerLength) {
					return -1;
				}
			} else {
				return -1;
			}
		}
		return packetLength;
	}

	public int getLength() {
		return length;
	}

	@Override
	public ByteBuf getProduce() {
		return buf;
	}

	private boolean isHeaderReadComplete(ByteBuf buf) {
		return !buf.hasRemaining();
	}

	@Override
	public boolean read(SocketSession session, ByteBuf buffer) throws IOException {

		if (!header_complete) {

			ByteBuf buf = this.buf;

			buf.read(buffer);

			if (!isHeaderReadComplete(buf)) {
				return false;
			}

			doHeaderComplete(session, buf);
		}

		if (!body_complete) {

			ByteBuf buf = this.buf;

			buf.read(buffer);

			if (buf.hasRemaining()) {
				return false;
			}

			doBodyComplete(buf);
		}

		return true;
	}

	@Override
	public void release() {
		ReleaseUtil.release(buf);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy